【笔记】《数据结构与算法图解》

《数据结构与算法图解》

  • 第一章 数据结构为何重要
    • 1.1 基础数据结构:数组
      • 1.1.1 读取
      • 1.1.2 查找
      • 1.1.3 插入
      • 1.1.4 删除
    • 1.2 集合:一条规则决定性能
  • 第二章 算法为何重要
    • 2.1 有序数组
    • 2.2 查找有序数组
    • 2.3 二分查找
    • 2.4 二分查找与线性查找
  • 第三章 大O记法
    • 3.1 大O:数步数
    • 3.2 常数时间与线性时间
    • 3.3 同一算法,不同场景
    • 3.4 第三种算法
    • 3.5 对数
    • 3.6 解释O(logN)
  • 第四章 运用大O来给代码提速
    • 4.1 冒泡排序
    • 4.4 冒泡排序的效率
  • 第五章 用或不用大O来优化代码
    • 5.1 选择排序
    • 5.4 选择排序的效率
    • 5.5 忽略常数
    • 5.6 大O的作用
  • 第六章 乐观地调优
    • 6.1 插入排序
    • 6.4 插入排序的效率
    • 6.7 总结
  • 第七章 查找迅速的散列表
    • 7.1 探索散列表
    • 7.4 处理冲突
    • 7.5 找到平衡
  • 第八章 用栈和队列来构造灵巧的代码
    • 8.1 栈
    • 8.3 队列

第一章 数据结构为何重要

数据是一个广义的术语,可以指代各种类型的消息,包括最基本的 数字和字符串。

数据结构则是指数据的组织形式。

1.1 基础数据结构:数组

数组是计算机科学中最基本的数据结构之一

一般数据结构都有以下4种操作(或者说用法)
读取、查找、插入、删除

操作的速度(即时间复杂度),并不按时间计算,而是按步数计算。

1.1.1 读取

根据内存地址一步找出该内存地址上的数据

1.1.2 查找

线性查找最多要找数组长度的步数,所以查找永远比读取要慢。

1.1.3 插入

往数组里插入一个新元素的速度,取决于你想把它插入到哪个位置上。

插入到末尾,只需要一步;插入到开头或中间,需要把后面的其他元素依次向后移动一格。所以插入到开头是最低效的。

删除则相当于是插入的反向操作。

1.1.4 删除

先删除数据然后再把它之后的所有元素向前移动一格。

1.2 集合:一条规则决定性能

集合:它是一种不允许元素重复的数据结构。
对于集合,插入操作需要先确定要插入的值不存在于其中。

第二章 算法为何重要

算法即就是某项操作的过程

2.1 有序数组

有序数组顾名思义,和第一章的数组几乎一样,唯一区别就是有序数组要求其值总是保持有序。

虽然插入的性能比不上常规数组,但在查找方面,有序数组却有着特殊优势。

2.2 查找有序数组

从左到右,逐个格子检查,到比它大就可以提早停止。

有序数组使用二分法查找,它比线性查找快得多。

2.3 二分查找

每次都找中间的元素做比较。

2.4 二分查找与线性查找

对于拥有100个值的数组来说,两种查找需要的最多步数如下所示。
线性查找:100步
二分查找:7步

第三章 大O记法

量化线性查找效率的更准确的方式应该是:对于具有N个元素的数组,线性查找最多需要N步。

3.1 大O:数步数

大O记线性查找为:O(N)

3.2 常数时间与线性时间

O(N)也被称为线性时间;O(N)也被称为常数时间。
简单来说,O(1)就是用来表示所有数据增长但步数不变的算法。

3.3 同一算法,不同场景

线性查找的最好情况是O(1),最坏的情况是O(N)。
若无特别说明,大O记法一般都是指最坏情况。

3.4 第三种算法

二分法查找的大O记法是:O(logN),也被称为对数时间。

3.5 对数

对数

3.6 解释O(logN)

O(logN)算法的步数等于二分数据直至元素剩余1个的次数。

第四章 运用大O来给代码提速

4.1 冒泡排序

冒泡排序
(1)指向数组中的两个相邻的元素(最开始是数组的头两个元素),比较它们的大小。
(2)如果它们顺序错了(即左边的值大于右边),就互换位置。如果顺序正确就什么都不用做。
(3)将两个指针右移一格。重复第(1)和第(2)步,直至指针到达数组末尾。
(4)重复第(1)到(3)步,直至从头到尾都无须再做交换,这时数组就排序好了。

4.4 冒泡排序的效率

冒泡排序效率的大O记法,是O(N平方)也被称为二次时间。

第五章 用或不用大O来优化代码

5.1 选择排序

选择排序
(1)从左至右检查数组的每个格子,找出值最小的那个。在此过程中,我们会用一个变量来记住检查过的数字的最小值(事实上记住的是索引)。如果一个格子中的数字比记录的最小值还要小,就把变量改成该格子的索引。
(2)知道哪个格子的值最小之后,将该格与本次检查的起点交换。第1次检查的起点是索引0,第2次是索引1,以此类推。
(3)重复第(1)(2)步,直至数组排好序。

5.4 选择排序的效率

选择排序比冒泡排序快一倍。
选择排序的效率是1/2 N平方步,大O记法:O(N平方)

5.5 忽略常数

大O记法忽略常数
选择排序的大O记法跟冒泡排序是一样的。

5.6 大O的作用

它能够区分不同算法的长期增长率

第六章 乐观地调优

6.1 插入排序

插入排序
(1)在第一轮里,暂时将索引1(第2格)的值移走,并用一个临时变量来保存它。这使得该去索引处留下一个空隙,因为它不包含值。在之后的轮回,我们会移走后面索引的值。
(2)接着便是平移阶段,我们会拿空隙左侧的每一个值与临时变量的值进行比较。如果空隙左侧的值大于临时变量的值,则将该值右移一格。随着值右移,空隙会左移。如果遇到比临时变量小的值,或者空隙已经到了数组的最左端,就结束平移阶段。
(3)将临时移走的值插入当前空隙。
(4)重复第(1)至(3)步,直至数组完全有序。

6.4 插入排序的效率

大O只保留最高阶的N
插入排序的效率是N平方+2N-2步,大O记法:O(N平方)

6.7 总结

懂得区分最好、平均、最坏情况,是为当前场景选择最优算法以及给现有算法调优以适应环境变化的关键。记住,虽然为最坏情况做好准备十分重要,但大部分时间我们面对的是平均情况。

第七章 查找迅速的散列表

7.1 探索散列表

散列表由一对对的数据组成。一对数据里,一个叫作键,另一个叫作值。

7.4 处理冲突

往已被占用的格子里放东西,会造成冲突。
一种经典的解决冲突的办法就是分离链接。当冲突发生时,我们不是将值放到格子里,而是放到该格子所关联的数组里。

7.5 找到平衡

散列表:O(1),但它既要避免冲突,又要节约空间。

第八章 用栈和队列来构造灵巧的代码

8.1 栈

栈存储数据的方式跟数组一样,都是将元素排成一行。只不过它还有以下三条约束。
只能在末尾插入数据。
只能读取末尾数据。
只能移除末尾数据。

你可以将栈看成一叠碟子:你只能看到最顶端的碟子的碟面,其他都看不到。另外,要加碟子只能往上加,不能往中间塞,要拿碟子只能从上面拿,不能从中间拿(至少你不应该这么做)。绝大部分计算机科学家都把栈的末尾称为栈顶,把栈的开头称为栈底

往栈里插入数据,也叫做压栈。你可以想象把一个碟子压在其他碟子上的画面。

从栈顶移除数据叫作出栈。这也是栈的限制:只能移除末尾的数据。

压栈和出栈可被形容为LIFO(last in,first out)后进先出。解释起来就是最后入栈的元素,会最先出栈。就像无心向学的学生,最迟到校的总是他,最早回家的也是他。

8.3 队列

FIFO(first in,first out)
•只能在末尾插入数据(这跟栈一样)
•只能读取开头的数据(这跟栈相反
•只能移除开头的数据(这也跟栈相反

只是个人的简单的读书笔记,如有错误感谢批评指正

你可能感兴趣的:(读书笔记,数据结构,算法)