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

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

问题:从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.算法笔记(三)算法学习技巧从开始学习算法已经有两三个多月的时间了,从简单到深入层次展开,层层优化,对算法的理解也在逐渐加深,不在那么片面,虽然现在还是片面一些,对它的了解也仅仅知道冰山一角,还有很多的内容需要我们去学习去挖掘。 思路 在学习前我们要尽可能快速阅读一遍要学习的书籍,这样不仅仅让我们知道了有哪些内容需要学习,同时也在https://www.code456.com/article/3598351.html
2.大一计算机专业学生,该如何自学数据结构和算法?不要一来就拿着《算法导论》开始啃,初学就去啃这些书肯定会很费劲。你一旦啃不下来,挫败感就会很强。 然后就放弃学算法了。 所以,入门的同学,我建议你找一些比较容易看的书来看,比如《大话数据结构》和《算法图解》。 不要太在意书写得深浅,重要的是能不能坚持看完。 《大话数据结构》 这本书最大的特点是,https://www.zhihu.com/question/454132632/answer/2341756722
3.算法的初学者教程算法入门算法的初学者教程 本文介绍了算法的基本概念,包括时间复杂度和空间复杂度,并详细讲解了数组、链表、栈、队列、哈希表和树等常见数据结构。接着,讨论了排序算法如冒泡排序、选择排序、插入排序和快速排序,以及查找算法中的顺序查找和二分查找。最后,概述了动态规划、贪心算法和回溯算法的应用,如最长公共子序列问题、https://blog.csdn.net/qq_35522002/article/details/130116043
4.初学者必学的算法基础教程初学者必学的算法基础教程 标签: 算法 算法与数据结构 收藏 概述 本文介绍了算法的基本概念和重要性,涵盖了算法的组成部分和不同类型,如搜索算法、排序算法和图算法。文章还解释了算法的时间复杂度和空间复杂度,并提供了示例代码和学习资源,帮助读者更好地理解和应用算法。 算法基础知识简介 什么是算法 算法是一https://www.imooc.com/article/362340
5.初学者应当掌握的算法LightAc7.LIS LCS 数字三角形 01背包 8.状压DP 和 树形DP 9.单调栈 单调队列 优化DP 10.树状数组 二维树状数组 11.素数筛 拓展欧几里得 中国剩余 12.线段树 初学者应当掌握的算法 算法内容 回到顶部 1.二分 + 二分答案 + 快速幂 回到顶部 2.C 到 C艹 各类容器及其原理(堆和set) https://www.cnblogs.com/lightac/p/10534745.html
6.算法详解(卷1)——算法基础(豆瓣)一整本书在讲分治算法,很细致,挺好的,也不厚 1 有用 三七李 2021-12-06 23:57:06 轻松愉快,适合复习(总算看懂主定理的证明了 3 有用 Echo毓歌 2021-05-28 02:54:29 感觉是对算法初学者最友好的书了 > 更多短评 14 条 我要写书评 算法详解(卷1)——算法基础的书评 ··· ( 全部1 条https://book.douban.com/subject/30424415/
7.helloalgo,一个免费的算法学习开源项目若您是算法初学者,从未接触过算法,或者已经有一些刷题经验,对数据结构与算法有模糊的认识,在会与 不会之间反复横跳,那么这本书正是为您量身定制!如果您已经积累一定刷题量,熟悉大部分题型,那么本书可助您回顾与梳理算法知识体系,仓库源代码可以 被当作“刷题工具库”或“算法字典”来使用。 https://developer.aliyun.com/article/1437987
8.AtCoder算法竞技平台简介腾讯云开发者社区ABC是给算法初学者参加的,ARC是给有一定算法基础的人参加的。 ABC和ARC都是四道题。ABC的C、D题和ARC的A、B题完全一样。 ARC对标Codeforces Div2,也就是说AtCoder的题目难度低于Codeforces。 与Codeforces不同的是,AtCoder没有Final System Test,参赛者提交程序后即可知道自己的程序是否正确。 https://cloud.tencent.com/developer/article/1164720
9.如何入门学算法?其实不然,万丈高楼平地起,任何高深的算法都要从基础算法学起,不可能一口吃个胖子,所以入门算法还是要从基础开始: 首先学习一门语言,例如C/C++或者Java,初学者学C++比较普遍。 学一本数据结构,数据结构书有很多,具体看什么书最好,因人而异,尽管很多人觉得严的书难以理解,但是无法否认,严的书是权威,所以仍然推荐https://www.jianshu.com/p/6b9f1be558c6
10.从零开始学算法(基于Python)最新章节李峰著主要的原因是初学者没有找到学习算法的门路,算法是计算机行业的前辈们智慧的精华,本身固然存在一定的复杂性,但是学习起来困难的主要原因还是讲解者讲得不到位。学习算法就好像我们上学的时候学习数学,虽然数学的复杂公式与逻辑对于学习者确实存在一定的难度,但是解题思路还是有规律可循的,通过对具体的题型分类,辅以大量的https://m.zhangyue.com/readbook/12675722/17.html
11.算法竞赛入门经典PDF扫描版电子书下载4.2.4 初学者易犯的错误 4.3 递归 4.3.1 递归定义 4.3.2 递归函数 4.3.3 C语言对递归的支持 4.3.4 段错误与栈溢出 4.4 本章小结 4.4.1 小问题集锦 4.4.2 小结 第2部分 算法篇 第5章 基础题目选解 5.1 字符串 5.1.1 WERTYU 5.1.2 TeX括号 https://www.jb51.net/books/155734.html
12.清华大学出版社图书详情本书是算法竞赛的入门和进阶教材,包括算法思路、模板代码、知识体系、赛事相关等内容。本书把竞赛常用的知识点和竞赛题结合起来,讲解清晰、透彻,帮助初学者建立自信心,快速从实际问题入手,模仿经典代码解决问题,进入中级学习阶段。全书分为12章,覆盖了目前算法竞赛中的主要内容,包括算法竞赛概述、算法复杂度、STL和基本http://www.tup.tsinghua.edu.cn/booksCenter/book_08163901.html
13.科学网—[转载]最实用的机器学习算法优缺点分析,没有比这篇说得更K 均值是基于样本点间的几何距离来度量聚类的通用目的算法。由于集群围绕在聚类中心,结果会接近于球状并具有相似的大小。 我们之所以推荐该算法给初学者,是因为它不仅足够简单,而且足够灵活,对于大多数问题都能给出合理的结果。 优点:K 均值是最为流行的聚类算法,因为它足够快速、足够简单,如果你的预处理数据和特征工https://blog.sciencenet.cn/blog-1396960-1170780.html
14.C语言入门的基本学习方法我个人认为在求解与实现一个小问题的时候,我们可以写出一个通用的模块处理不同的Data.当然比如某些经常用到的,基于数据结构的一些常用算法我们可以写出来在开发的时候我们可以直接把预先编写的模块插入到我们的程序中去,这不也是大大低了开发周期吗?初学者完全可以根据自己的需求来编写一个自定义库.好了,说了这些,有https://mip.oh100.com/kaoshi/c/560623.html
15.新手必看的Top10个机器学习算法学会了你就是老手当面对各种各样的机器学习算法时,初学者通常会问这样一个问题:”我应该使用哪种算法?“这个问题的答案取决于许多因素,包括:(1)数据的规模、质量和性质;(2)可用计算时间;(三)任务的紧迫性;以及(4)如何处理数据。 在尝试不同的算法之前,即使是经验丰富的数据科学家也无法判断哪种算法会表现最好。虽然还有许多其他https://www.51cto.com/article/600359.html
16.GitHubkrahets/hello“一本通俗易懂的数据结构与算法入门书,引导读者手脑并用地学习,强烈推荐算法初学者阅读。” —— 邓俊辉,清华大学计算机系教授 “如果我当年学数据结构与算法的时候有《Hello 算法》,学起来应该会简单 10 倍!” —— 李沐,亚马逊资深首席科学家 贡献 https://github.com/krahets/hello-algo
17.趣学算法(第2版)本书既适合那些对算法有强烈兴趣的初学者,也适合觉得算法晦涩难懂、无所适从的人,还适合作为高等院校计算机及相关专业的算法教材。读者阅读本书,不仅能够理解经典的算法设计,而且能获得足够多的实用技巧,以便更好地分析和解决问题,为学习更高深的算法奠定基础。 https://www.epubit.com/bookDetails?id=UB7d85fa69dcbd8
18.支持C++,Java,Python,Go,JavaScript等多语言版本,从此算法学习但我能设身处地的感受到:即使有这样一个整体规划,对于一位初学者甚至算法老手寻找合适自己的题目也是很困难,时间成本很高,而且题目还不一定就是经典题目。 对于刷题,我们都是想用最短的时间按照循序渐进的难度顺序把经典题目都做一遍,这样效率才是最高的! 所以我整理了leetcode刷题攻略:一个超级详细的刷题顺序,https://gitee.com/yuandreams/leetcode-master