第一本算法书第一章学习笔记_20201022

我的第一本算法书读书笔记_201022

第一章:数据结构

这一章主要讲解七种常见的数据结构:链表,数组,栈,队列,哈希表,堆,二叉查找树

1-1 什么是数据结构

  • 数据存储于内存时,决定了数据的顺序和位置关系的便是“数据结构”;
  • 数据存储于内存时,选择合适的数据结构以提高内存的利用率;

1-2 链表

链表中,数据呈线性排列,数据的添加和删除都比较方便,但是访问比较耗时。

链表访问数据:
- 每个数据都有一个指针指向下一个数据的内存地址;
- 数据存储是离散的,不用存储在连续的空,也因为这个特征在访问数据时只能从第一个数据开始沿着指针顺序访问;

链表数据添加和删除
添加删除数据都是通过改变数据的指针来完成,删除数据后,其实这个数据还是占据着内存空间的,但是没法访问,当需要使用这个内存空间时,只需要用新数据去覆盖就好了。
链表概念图
运行时间:

  • 访问时间:O(n),因为使用线性查找
  • 添加删除数据:O(1),因为只需要更改数据的指针

其他类型的链表:

  • 循环链表(环形链表):首尾相连,用于存放数量固定的最新数据
    **- 双向链表:**每个数据都有两个指针,指向前后向数据,使用这种数据可以从前往后或者从后往前两种方式遍历数据,但是缺点是会造成存储空间的增加,以及在增加删除数据时需要改变更多的指针。

1-3 数组

线性排列数据结构,与链表相反,访问数据简单,但是增加删除耗时。
数组概念图
在这里插入图片描述
数组访问:

  • 存储在连续的内存空间,因为这个特性,数组的下标和内存地址是一一对应的,所以我们可以通过下标计算出内存地址而随机访问数组中的数据。
    数据添加删除:

  • 数据添加:

    数组末尾添加一个存储空间—>把目标位置后面的现有数据一个一个后移—>把目标数据插入空出来的位置

  • 数据删除:

    删除数据—>把空位后面的数据一个一个往前移—>删除多余的空间

运行时间:
访问时间:O(1)
添加删除时间:O(n)

链表和数组的选择:
我们可以根据实际使用中那种操作比较频繁来选择合适的的数据结构。

1-4 栈

栈也是线性数据结构,像一摞书,后面的书总是放在上面,遵循后进先出(LIFO)的规则。

栈的概念图:
在这里插入图片描述
在这里插入图片描述
栈的访问:
栈只能访问最上层数据,要想访问中间的数据,必须先做出栈操作,将目标数据放到最上层。
栈的添加和删除:
添加和删除只能在一段进行
栈的应用场景:
在使用最新数据的场景,比如匹配括号,遇到左括号做入栈,遇到又括号将栈顶部的做阔好做出栈操作,这样就将括号匹配了起来。另外一个场景是深度优先搜索算法,将最新的数据作为候补点,后不但的管理可以使用栈。

1-5队列

队列也是一种线性数据结构,与栈的区别是队列是一端进,另一端出,遵循先进先出(FIFO)的规则,
队列概念图:
入队
出队
队列数据的添加和删除:
队列一端进,另一端出,操作数据也是有限制的。

队列的访问:
队列的访问也是需要做出队操作,将目标数据放到首位后才能访问。

队列的应用:
先来的数据先处理符合常见思路,应用广泛,应用例子是广度优先搜索算法,通常将搜索候补中选择最早的数据作为下一个顶点。

1-6哈希表

哈希表这种数据结构常用于“哈希函数”中,可以使数据的查询效率得到显著提升。
哈希表存储的是键值对,键一般作为数据的标识符,值一般是数据的内容。

哈希表与数组的对比:
如果用数组存储键值对,因为数组是线性数据结构,所以在查找数据的时候,是从上往下查找的,比较耗时。

哈希表的数据存储过程如下:
准备好一个固定长度的空数组–>存数据时先根据"哈希函数"计算数据的"hash值"(key)–>“hash值” mod 'len(array)'作为数据在数组中存储的位置–>当位置出现冲突时,使用链表在已有数据后面存储新的数据。
哈希表的查询过程如下:
使用哈希函数计算出数据的"hash值"–>“hash值 mod len(array)”就知道了数据存储位置–>如果这个位置没查到,那么就沿着这个位置后面的链表线性查找–>找到后拿出来得到value。

hash表要设置合适的数组空间:
给哈希表的数组太小,会造成冲突,这样也就增加了线性数据结构链表的使用率,如果数组太大,就会占用内存空间,造成内存的浪费,所以选择合适的数组大小非常重要。

哈希表冲突的解决方案:
1.链地址法:就是我们上面解释过的那种方法。
2.开放地址法:冲突时多次使用“哈希函数或者线性探测法”找到一个候补地址(数组上暂时空闲的地址)

无法根据哈希值计算出原值时哈希表必须遵守的规则吗?
不是的,上面这个规则只是将哈希表应用于密码等安全方面才使用的规则。

1-7堆

堆是一种树形结构,用于优先队列(例如广度优先搜索),优先队列这种数据结构可以自由存入数据,但是在取出时,必须按照从小到大顺序取出,数据存储在堆的各个节点中。
堆的概念图:
在这里插入图片描述

堆的特征:
1.一个节点最多两个子节点;
2.排列顺序为从上到下,从左到右;

堆的数据存储:
往堆里存数据时,子节点必须大于父节点,这就意味着根节点存的数据时最小的,存数据是从最后一行靠左的位置存储,当最后一行没有空位置时,另起一行靠左存储,然后将这个数据与其父节点做比较,如果子节点小,就将子节点与父节点互换;

堆的数据取出:
取出数据时,取出的是最小的,也就是取出顶点位置,然后将右下角的数据补充到根节点;
如果父节点大于字节点,就将父节点与字节点中较小的进行交换,重复这个操作,直到不需要再交换;

堆存储和取出的时间复杂度:
假设堆中有n个数据,根据堆的特征,堆的层高为log以2为底n的对数加一,所以取出一个数据的时间复杂度为O(1),重构堆的时间复杂度为log以2为底n的对数;
存储一个数据一样的,时间复杂度也是log以2为底n的对数;

堆的应用场景:
适用于频繁从管理数据中取出最小值的场景,比如狄克斯特拉算法(从数据中取出距离顶点距离最近的点)

1-8 二叉查找树

二叉树是图的树形数据结构,是二分查找算法思想的树形体现
二叉树的概念图:
在这里插入图片描述
二叉树的特征:
1.每个节点最多有两个子节点
2.节点中可能有相同的数字
3.每个节点的值大于其左子树上的任意一个节点值;
4.每个节点的值小于其右子树上的任意一个节点值
3,4点可以归纳为左边存小的,右边存大的,这一点区别于堆的上小下大。

二叉树的数据查找:
查找最小值,从顶点开始往左下的末端寻找;
查找最大值,从顶点开始往右下的末端寻找;
查找中间值:从顶点开始,一一比较,查找值小于节点就往左走,大于节点就往右走。
二叉树的数据添加:
将要添加的数据从顶点开始进行比较,如果数据较小,往左下方向移动比较,若数据大就往右下方向移动;

二叉树的数据删除:
1.没有子节点,直接删除
2.只有一个子节点,删除目标节点,然后将子节点填补目标节点的位置
3.有两个子节点,删除目标节点,然后将这个节点左子树上最大的值添加到这个空出来的位置(往往要使用到递归操作),当然也可以移动右子树的最小值。

二叉树的时间复杂度:
二叉树比较和移动的次数取决于树高,当树均匀分布时,树高为log以2为底n的对数,时间复杂度O(logn),但是如果树朝向一边偏的话,时间复杂度就是O(n)

二叉树的扩展:
平衡二叉树:修正分布不均衡的树使其均衡,提高查找效率
B树:子节点的个数可以自由设定,并且形状均衡

猜你喜欢

转载自blog.csdn.net/a18829292719/article/details/109215805