《我的第一本算法书》序章及第一章笔记
序章
0.1什么是算法
1.算法是解决问题得精确的方法。对于程序与算法,程序是以编程语言编写得,可以在计算机上运行,而算法则是以人类能够理解得方式来描述得。
2.排列整数得算法:排序
- 选择排序
- 算法的设计:无论再复杂的问题,对于计算机而言,也是由基本命令组合而成的。
3.如何选择算法:我们最为重视的算法的运算时间。
0.2运算时间的计算方法
- 如何求得运算时间:我们将计算“一步”作为计算的基本单位,利用从开始到结束经过了多少步来求得算法的运行时间。
- 运算时间的表示方法:对于一个算法来说,运算时间与输入数据n的最大次方数成正比。当运算时间中的n的最大次方是n的3次方是,运算时间可以可以用O(n的三次方)来表示。如果最大次方数是n的二次方,则可以用O(n的二次方来)表示。以下同理。
第一章
1.1
什么是数据结构:
- 数据存储在内存里,就像存在箱子里一样。而决定数据结构和位置关系的便是“数据结构”。
- 本书将使用7种数据类型来使内存利用率最大化。
1.2链表
链表中的数据呈线性排列,分散储存。在链表中,数据的添加和删除比较方便,但比较耗费时间。
- 链表上的数据呈一条线,指向一个方向。第一个数据有一个指针指向第二个,第二个有一个指针指向第三个,依次排列,最后一个数据不含指针。访问时是顺序访问,想访问某个数据,必须从一个开始访问。而要添加数据到某一个位置n则需要将n-1位置数据的指针指向该数据,并把该数据的指针指向原本位置n的数据。而删除位置n的数据则是令位置n-1的指针指向位置n+1的数据。
- 对于链表来说,假设数据量为n,如目标数据在最后,需要时间为O(n)。而杀出和添加与数据量n无关,只需要花费O(1)的时间。
- 除了基本链表外还有循环链表(环形链表),以及双向链表。
1.3数组
数组同样呈线性排列。其访问数据很简单,但添加和删除数据比较耗功夫。
- 数据是按照顺序存储在内存的连续空间内。
- 我们可以根据数据的下表直接访问目的数据,这叫做“随机访问”。
- 添加某个数据需要在数组末尾加上存储空间,再将已有数据一个个移开。再在空出的位置上写入所需的数据。删除数据需要将其反过来。
- 其访问时间非常短,只要O(1)。但在添加和删除数据时需要O(n)的时间,n为目标位置之后的数据数。
小总结
1.4栈
栈也是一种呈线性排列的数据结构。从栈里取数据就像从装满书的木桶里取书。你只能把新书放在栈的最上面,取书也只能从最上面的新书开始取。往栈中添加数据的行为交入栈,取出数据叫出栈。其删除和添加数据的操作均只能在在一端进行。
- 像栈这种最后添加的数据最先被取出的,交“后进先出”结构,英文简称为LIFO(last in first out)。
-
在以上实例中栈有很好的应用。
1.5队列
队列就像一群人通过一个管道,只能从入口端一个一个地进入,即入队(输入数据),只能从出口端一个一个地离开管道(删除数据),被称为出队。
- 这种叫做先进先出的结构英文简称叫FIFO。
- 对于队列来说,它也有一定的限制。即队列无法直接访问位于中间的数据,必须通过出队操作将数据编程首位后才能访问。
- FIFO的结构可以用在4.2的广度优先搜索算法上,它会从搜索候补中找出最早的数据作为下一个顶点。
1.6哈希表
哈希表可用于5.3的哈希函数。哈希表的知识中有一些关于链表和数组的知识。
举例:我们要从n个学生中查询某个学生的性别。我们将学生的姓名视作键(key),键通常用于判别数据的标识符。性别视作值(value),通常被当作数据的内容。
我们可以准备5个箱子一样的数组我们可以利用哈希函数(需要用到第5章的知识)算出第一个学生的哈希值,mod5(除5取余)
得3,放在3号箱子里,再重复前面操作。如果有的键的mod5值相同,即发生了“冲突(哈希冲突)”,可将其放入同一个箱子中,利用链表在已有数据后面继续存储新的数据,全部完成后,哈希表也制作完成了。
对哈希表进行查询时,要先算出所查询键的哈希值,再mod运算,然后在该箱子里进行线性查找。
注意:使用哈希表的时候,数组的空间(即箱子的个数)不宜太大太或太小,太大浪费空间,太小则会经常发生哈希冲突。
补充:
- 发生哈希冲突,用链表在已有数据后面插入新数据的方法叫“链地址法”。
- 还有其他的解决冲突的方法,如开放地址法。当冲突发生时,会立即就算除一个候补地址(增加一个箱子),若仍有冲突,继续增加箱子。
1.7堆
堆是一种图状的树形结构。常用于实现优先队列。优先队列是一种可以自由添加数据,但去除数据时要从最小值开始按顺序取出的数据结构。每个顶点被称为“结点”。数据就在结点之中。
- 堆中的每个结点最多有两个子结点。
- 树的形状取决于数据的个数。
- 从左到右,从上到下,结点上的顺序依次增加。
- 子结点上的顺序必然大于父结点。
- 注意如何对堆进行排列顺序。
注意:
- 堆中最顶端的数据无论什么时候都最小,因此无论数据有多少,取出最小值的时间复杂度都为O(1)。
- 取出数据后,要把最后的数据移到最顶端,然后一边比较它与子结点数据的大小,一边往下移动。假如数的数据量为n,根据堆的形状特点可知树的高度为以2为底的n的对数,那么重构树的时间复杂度为O(log n)。
- 添加数据时,则需在堆的最后添加数据,再一边比较它与父结点数据的大小,一边往上移动,知道满足堆的条件。运行时间也是(log n)。
举例:堆这种数据结构石贺于需要频繁地从管理的数据中取出最小值得情况,例如4.5得狄克斯特拉算法,每一步都需要从候补顶点中选择距离起点最近得那个顶点,此时可用。
1.8二叉查找树
二叉查找树(又被叫作二叉搜索树或二叉排序树)是一种数据结构。
性质:
- 每个结点的值均大于其左子树上任意一个结点得值。
- 每个结点的值均小于其右子树上任意一个结点的值。
注意:
- 对于二叉查找树来说,在查找数据或者寻找合适添加数据的位置时,只要将其和现有的数据比较大小,就能知道该往那边移动。
- 比较的次数取决于树的高度。当结点树为n,且树形状较为均衡时,比较大小和移动次数最多就是(以2为底n的对数)。时间复杂度为O(log n)。但是树偏向于单侧纵向延伸时,时间复杂度就会变成O(n)。
补充:
- 有以二叉查找树为基础拓展的数据结构,比如"平衡二叉查找树"。这种数据类型可以修复原本形状不平衡的树,使其均衡。
- 另外,存在把子结点拓展为m,且形状均衡的树叫B树。