读《算法图解》—对算法的一些基本理解前端学习笔记

关于这点,我们来看一个实际的例子。

问题:从1~100个数中猜出某个我现在想到的数字,我只会告诉你「大了」,「小了」,「对了」,最快需要几次猜到?

解决这个问题有多种方案,如果你运气好,也许1次就猜对了,运气差也许会需要100次。有一种叫做「二分查找」的算法非常适合解决这类问题。

定义:二分查找是一种算法,其输入是一个有序的元素列表,如果元素包含在列表中,二分查找返回其位置,否则返回null.

分析:简单查找模式:从1开始往上猜,又称「傻找」,最多会需要99次猜测。二分查找:每次猜最大,最小数字的中间值,由此每次可排除一般的可能性,最多只需要7次就可猜对。

代码实现

算法常常和数据结构挂钩。在介绍数据结构之前,我们需要先理解内存的工作原理,这样有助于我们理解数据结构。

我们可以把计算机的内存想象成有很多抽屉的柜子,每个柜子都有其编号。

当需要将数据存储到内存时,我们会请求计算机提供存储空间,计算机会分配一个柜子给我们(存储地址),一个柜子只能存放一样东西,当需要存储多项连续的数据时,我们需要以一种特殊的方法来请求存储空间,这就涉及到两种基本的数据结构—数组和链表。

「数组」这个概念我们很熟悉,在我们的平日的开发过程中会经常用到,不过暂时忘记JavaScript中的Array吧。我们来看看数组的本质。

使用数组意味着所有的存储事项在内存中都是相连的。这样做的优点是,如果我们知道某个存储事项的索引,我们只需要一步就能找到其对应的内容。但是缺点也显而易见,如果计算机开始为我们的数组分配的是一块只能容纳三项的空间,当需要存储第四项的时候,会需要把所有内容整体移动到新的分配区域。如果新的区域再满了,则需要再整体移动到另外一个更大的空区域。因此有时候在数组中添加新元素是很麻烦的一件事情。针对这个问题常见的解决方案时预留空间,不过预留空间也有两个问题:

*可能浪费空间;*预留的空间可能依旧不够用;链表链表中的元素可以存储在任何地方,链表的每个元素都存储了下一个元素的地址,从而使得一系列的内存地址串在一起。

链表的劣势恰恰是数组的优势,当需要随机读取元素时,数组的效率很高。(数组中的元素存储的内存地址相邻,可容易计算出任意位置的元素的存储位置)。

前面介绍的「二分查找」的前提是查找的内容是有序的,在熟悉了数组和链表后,我们来学习第一种排序算法—选择排序。

定义遍历一个列表,每次找出其中最大的那个值,存入一个新的列表,并从原来的列表中去除该值,直到排完。

示例代码

递归是一种优雅的问题解决方法。其优雅体现在它让解决方案更为清晰,虽然在性能上,有些情况下递归不如循环。

递归由两部分组成:

上面提到,递归可能存在性能问题,想要理解这一点,需要先理解什么是「调用栈」。

「栈」是一种先入后出(FILO)简单的数据结构。「调用栈」是计算机在内部使用的栈。当调用一个函数时,计算机会把函数调用所涉及到的所有变量都存在内存中。如果函数中继续调用函数,计算机会为第二个函数页分配内存并存在第一个函数上方。当第二个函数执行完时,会再回到第一个函数的内存处。

我们再看看「递归调用栈」:

使用递归很方便,但是也要出代价:存储详尽的信息需要占用大量的内存。递归中函数会嵌套执行多层函数,每个函数调用都要占用一定的内存,如果栈很高,计算机就需要存储大量函数调用的信息,这就是为什么有的语言会限制递归最多的层数。

如果所有函数都是尾调用,那么完全可以做到每次执行时,调用记录只有一项,这将大大节省内存。这就是"尾调用优化"的意义。

在正式讲解「快速排序」之前,我们先介绍一下「分而治之」这种方法。「分而治之」(divideandconquerD&C)是一种著名的递归式问题解决方法。只能解决一种问题的算法毕竟作用有限,D&C可能帮我们找到解决问题的思路。

运用D&C解决问题的过程包括两个步骤:

我们以快速排序为例来看看,如何运用分而治之的思维。

在编程语言中,存在另外一种和数组不同的复杂数据结构,比如JavaScript中的对象,或Python中的字典。对应到计算机的存储上,它们可能可以对应为散列表。

要理解散列表,我们需要先看看散列函数。

散列函数是一种将输入映射到数字,且满足以下条件的函数:

散列函数准确的指出了数据的存储位置,能做到这个是因为:

我们可以把散列表定义为::使用散列函数和数组创建了一种数据结构。::

散列表也被称为「散列映射」,「映射」,「字典」和「关联数组」。

但是就像上面提到的,需要连续内存位置的数组存储空间毕竟有限,散列表中如果两个键映射到了同一个位置,一般做法是在这个位置上存储一个链表。

由于散列函数的存在,散列表中数据的查找变得非常快,散列函数值唯一,本身就是一种映射,基于这些,散列表可用作以下用途:

使用散列表页存在一些注意事项:

在平均情况下,散列表的查找速度和数组一样快,而插入和删除速度和链表一样快,因此它兼具二者的优点。但是在最糟的情况下,散列表的各项操作速度都很慢。

要想让散列表尽可能的快,需要避免冲突。想要避免冲突,需要满足以下两个条件:

如果填装因子大于1意味着商品数量超过数组的位置数。一旦填装因子开始增大,就需要在散列表中添加位置,这被称为调整长度。

一个不错的经验是,当填装因子大于0.7的时候,就调整散列表的长度。

良好的散列函数让数组中的值呈均匀分布,不过我们不用担心该如何才能构造好的散列函数,著名的SHA函数,就可用作散列函数。

在大多数编程语言中,散列表都有内置的实现。下面我们看看散列表的用途。

广度优先算法是图算法的一种,可用来找出两样东西之间的最短距离。在介绍这种算法之前,我们先看看什么叫图。

图由节点(node)和边(edge)组成,它模拟一组连接。一个节点可能与众多节点直接相连,这些节点被称为邻居。有向图指的是节点之间单向连接,无向图指的是节点直接双向连接。

在编程语言中,我们可以用散列表来抽象表示图

广度优先搜索用以回答两类问题:

我们还是举例来说明该如何运用广度优先搜索。

芒果销售商问题如果你想从你的朋友或者有朋友的朋友中找到一位芒果销售商,涉及关系最短的路径是什么呢?

编码实现

constgraph={};graph.you=['alice','bob','claire'];graph.bob=['anuj','peggy'];graph.alice=['peggy'];graph.claire=['thom','jonny'];graph.anuj=[];graph.peggy=[];graph.thom=[];constisSeller=name=>name[name.length-1]==='m';constsearch=(name,graph)=>{constiter=(waited,visited)=>{if(waited.length===0){returnfalse;}const[current,...rest]=waited;if(visited.has(current)){returniter(rest,visited);}if(isSeller(current)){console.log(`${current}isamangoseller!`);returntrue;}visited.add(current);constpersonFriends=graph[current];returniter([...rest,...personFriends],visited);};returniter(graph[name],newSet());};search('you');上面的编码中涉及到了一种新的数据结构——队列。

队列队列的工作原理和现实生活中的队列完全相同,可类比为在公交车前排队,队列只支持两种操作:入队和出队。队列是一种先进先出的(FIFO)数据结构。

散列表模拟图散列表是一种用来模拟图的数据结构

提到图就不得不说一种特殊的图——树。

广度优先搜索只能找出最短的路径,但是它却并不一定是最快的路径,想要得到最快的路径需要用到狄克斯特拉算法(Dijkstra’salgorithm)

在狄克斯特拉算法算法中,每段路径存在权重,狄克斯特拉算法算法的作用是找出的是总权重最小的路径。

平时我们使用地图软件导航到某个我们不熟悉的地点时,地图软件往往会给我们指出多条路线。直达但是绕圈的公交并不一定会比需要换乘的地铁快。

狄克斯特拉算法的使用步骤如下:

狄克斯特拉算法涉及到的这种拥有权重的图被称为「加权图」不存在权限的图被称为「非加权图」。

狄克斯特拉算法算法只适用于有向无环图。不能将狄克斯特拉算法算法用于负权边的情况。

判断近似算法优劣的标准如下:

以下是NP完成问题的一些特点,可以帮我我们识别NP完全问题:

还有一种被称作「动态规划」的思维方式可以帮我们解决问题这种思维方式的核心在于,先解决子问题,再逐步解决大问题。这也导致「动态规划」思想适用于子问题都是离散的,即不依赖其他子问题的问题。

动态规划使用小贴士:

本书对KNN也做了简单的介绍,KNN的合并观点如下

读完本书,对算法总算有了一个入门的理解,当然算法还有很多值得深入学习的地方,以下是作者推荐的一些方向。

《算法图解》确实是一本比较好的算法入门书,不枯燥,又能让人有收获就能激励出人的学习欲望,学习算法单阅读本书肯定还是不够的,

THE END
1.数的分流(7)——左右课率,正负名之以正负术入之。 正负术曰:今两算得失相反,要令正负以名之。正算赤,负算黑,否则以邪正为异。 方程自有赤、黑相取,法、实数相推求之术。而其并减之势不得广通,故使赤、 黑相消夺之,于算或减或益。 正负的概念,实际上在“盈不足”算法中已经有了雏形,即对盈、朒两势维乘之后,达到不盈不朒的状态,https://zhuanlan.zhihu.com/p/92512462
2.分而治之算法一言以蔽之:分治法的设计思想是,将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。 2.分而治之的重点: 看是否能够发现重复的子问题,能否发现大问题存在的循环子结构,如果发现就把原问题转化为很简单的小问题。 是否能划分步骤(不同步骤不同解决方法),因为单个步骤往往比整个https://www.jianshu.com/p/038352946ba3
3.分而治之的算法(DevideandConquer)分而治之的算法(Devide and Conquer) 分治法 分治法是一种一般性的算法设计技术,它将问题的实例划分为若干个较小的实例(最好拥有相同的规模),对这些较小的实例递归求解,然后合并这些解,以得到原始问题的解。许多高效的算法都基于这种技术,虽然有时候它的适应性和效率并不如一些更简单的算法。https://blog.csdn.net/huanghanqian/article/details/78828788
4.基于SmithWaterman算法的并行分而治之生物序列比对算法生物序列比对 动态规划 分而治之 并行处理 内存空间https://www.cnki.com.cn/Article/CJFDTotal-JEXK200402005.htm
5.什么是分率此题中的1/8是分率是小林与小红身高的差去除以小红的身高,1/8是比值,把小红身高数看成单位“1”,“小红比小林矮几分之几”是把小林身高数看成单位“1”,应拿两人身高差去除以小林的身高数,得1/9。这里的 1/9也不是一般分数,而是表示两个数比值的分数。https://xue.baidu.com/okam/pages/strategy-tp/index?strategyId=140962423263312&source=natural
6.经典优化算法之分治法(DivideandConqueAlgorithm)分治分治,即分而治之。分治,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。这个技巧是很多高效算法的基础,如排序算法(快速排序,归并排序),傅立叶变换(快速傅立叶变换)……直接说就是将一个难以直接https://cloud.tencent.com/developer/article/1523170
7.陈景辉:算法之治:法治的另一种可能性?因此,我的结论将是:算法之治不但不是法治的较优越样态,甚至它都无法被视为真正的法治,它只不过是一种“法制”。尽管它是更先进、更优越、更隐蔽的法制,但它始终还是需要被小心警惕的法制,而不是应当被热情拥抱的法治。 一、法律的算法化:三个规范性理由https://www.legal-theory.org/?mod=info&act=view&id=26587
8.Awesome针对空间,无非就一个办法:大而化小,分而治之(hash映射),你不是说规模太大嘛,那简单啊,就把规模大化为规模小的,各个击破不就完了嘛。 至于所谓的单机及集群问题,通俗点来讲,单机就是处理装载数据的机器有限(只要考虑cpu,内存,硬盘的数据交互),而集群,机器有多辆,适合分布式处理,并https://github.com/Ty-Chen/Awesome-Backend/blob/5ad253a0f2e82d9b83892a60e01a1e0a855d70b3/Data%20Structure%20and%20Algorithm.md
9.2023年中国保险业数字化转型研究报告而此时,领域驱动设计(DDD)作为一种领先的架构设计方法,通过领域实体聚合、限界上下文建模等手段明晰有效的微服务边界,并建立业务架构与技术架构间的映射关系。每个业务领域作为独立的微服务,通过API实现与其他业务的灵活、高效交互。微服务架构与DDD相辅相成,为中台建设提供分而治之的整体思想、精益迭代的演进理念,成为https://36kr.com/p/2382894555673096
10.2022网络治理专题(答题纯享版)*这里我的动词是影响,而不是限制之类完全负面词汇,就是提醒大家,算法并不是造成信息茧房的唯一因素,要时刻谨记辩证思维哈! 算法窄化用户信息获取路径包括两方面:一是信息定制化意味着“自主权”让渡,看与不看看什么由算法决策,从而构建了一个由算法和个人共同决定的拟态环境,平台便通过算法推荐实现算法与商业价值的https://weibo.com/ttarticle/p/show?id=2309404830345634906292
11.算法学习减治·分治·变治51CTO博客经典优化算法之分治法(Divide-and-Conque Algorithm) 转载|【算法】分治法(Divide-and-Conquer Algorithm)经典例子分析 从字面上分析就可以看到有哪些步骤: 分-分解-将问题分解为规模更小的子问题,子问题最好相同或相似; 治-求解-将这些规模更小的子问题逐个击破; https://blog.51cto.com/u_14328065/2884404
12.高一乘杨东︱应对元宇宙挑战:数据安全综合治理三维结构范式多元共治是智能社会治理的题中应有之义,也是破解“治理赤字”的重要法宝。[36]在欧盟的立法模式下,数据被分为个人数据与非个人数据,前者由《通用数据保护条例》(GDPR)保护,而后者由《非个人数据自由流动条例》保护,公共数据纳入基础设施予以保护。然而,个人数据与非个人数据的边界越来越模糊,通过算法分析非个人数据https://www.ccps.gov.cn/bkjd/xzglgg/xgglgg2022_3/202203/t20220325_153412.shtml
13.论坛·DTCC 2022中国数据库技术大会即将召开,120+精选案例抢先看 ·【技术栈公益直播第五十期】人工智能在线下零售智慧门店的技术研究及商业应用落地 ·【在线技术沙龙】开源小秀场系列沙龙活动(第二期) ·求助-天干地支的计算 ·awk数组 ·SDDC之基础架构硬件选型 http://www.chinaunix.net/
14.五大常用算法之一:分治算法分治法是计算机科学中非常重要的算法。字面上的解释是“分而治之”,即将一个复杂的问题分为两个或两个以上相同或相似的子问题,然后将子问题分为更小的子问题。。。直到最后一个子问题可以简单地直接解决,原始问题的解决方案就是子问题的解决方案的结合。这一技能是许多高效算法的基础,如排序算法( 快速排序, 傅https://www.tulingxueyuan.cn/tlzx/jsp/3793.html
15.《中国社会科学文摘》2023年第9期目录价值哲学视域中的算法歧视与社会公正 孙伟平 作者单位:上海大学智能哲学与文化研究院、马克思主义学院,摘自《哲学研究》2023年3期 算法的认识论逻辑 吴畏 作者单位:华中科技大学哲学学院,摘自《哲学动态》2023年3期 数据、平台媒介与公共领域的危机 董山民 作者单位:浙江工商大学马克思主义学院,摘自《广州大学学报》2023年https://cssn.cn/dkzgxp/zgxp_zgshkxwz/2023n/202309/t20230927_5688327.shtml