这是一本算法领域的经典著作,全面介绍了关于算法和数据结构的必备知识,从编程基础到算法入门,样样俱全,并特别针对排序、搜索、图处理和字符串问题进行了详细论述,涉及的算法和问题包括了DSA的所有基础,内容非常多。全书600多页,6章,涵盖了程序员应该知道的50个算法,且提供了实际的代码实现(Java)。
第1章 基础 代码
1.1 基础编程模型
介绍学习算法和数据结构所需的基本工具
模块化编程:数据抽象、抽象数据类型(ADT):背包、队列、栈
庞大、复杂的问题:理解和定义问题、控制问题的复杂度、将难题分解为易于解决的子问题
算法分析:为一项任务选择最合适的算法,知道算法的理论性能
基础编程模型:使用的语言特性、软件库、操作系统特性
执行一个Java程序,必须先使用javac命令编译它,生成Java字节码,然后使用java命令运行它
一段Java程序:类,静态方法库,一个数据类型
原始数据类型:int double char boolean long short byte float
隐式赋值语句:++ -- 等
double a[][] = new double[m][n]; 直接创建二维数组
数值类型的变量、数组的默认值都是0
递归:1.递归有出口:最简单的情况;2.递归在渐变,收敛,规模更小的子问题;3.递归的子问题与父问题间无交集
静态方法库:定义在一个Java类中的一组静态方法 模块化编程
最佳实践之一:每个静态方法库中都包含一个main()函数,来测试库中所有方法 单元测试
API的目的,将调用和实现分离
标准输入(StdIn)、标准输出(StdOut)、命令行参数、格式化输出(printf)
重定向输入、重定向输出、管道
数据抽象 --> 面向对象编程
1.2 数据抽象
Java使用class关键字构造被称为“引用类型”的数据类型,-- 面向对象编程 (引用类型 <--> 原始数据类型)
抽象数据类型:数据成员必须都是private
使用抽象数据类型:注意力集中在API描述的操作上,而不关心数据表示
实现抽象数据类型:注意力集中在数据本身,并实现对该数据的各种数据
对象是能够承载数据类型的值的实体,对象三大特性:状态、标识、行为
实例方法的触发,都是和对象相关的
静态方法主要用于实现函数(数学函数等),非静态(实例)方法主要作用是实现数据类型的操作
静态方法调用使用类名(大写字母开头),非静态方法调用使用对象名(小写字母开头)
引用类型的赋值,不会创建新对象,只是创建该引用的一个副本,“别名”:两个变量指向同一个对象
对象作为参数,按值传递,无法改变原始引用,但Java作为引用类型的对象,会改变原对象的值。
Java中,对象数组是一个由对象的引用组成的数组,而非所有对象本身组成的数组。
利:对于大对象,移动引用而非对象本身,提高效率
弊:对于小对象,获取信息时,都通过引用,间接操作,会降低效率
几何对象
计算几何学
类型参数<泛型>
使用抽象数据类型:使代码更加简洁清晰
将大型程序分解为能够独立开发和调试的小型模块
接口继承:实现类继承的是接口
子类继承:基类派生类
Object类 toString() equals() getClass() compareTo() hashCode()...
封装类型:Boolean Byte Character Double Float Integer Long Short
equals():定义一种等价关系 自反性、对称性、传递性、一致性、非空性
自动内存管理:Java垃圾回收,GC策略,记录孤儿对象,然后释放其内存到内存池
异常、断言、契约式设计
Java中创建引用只能new,修改引用只能通过赋值
1.3 背包、队列和栈
泛型:参数化类型
自动装箱:原始数据类型转化为封装类型
自动拆箱:封装类型转化为原始数据类型
背包:无序,无删除操作
队列:FIFO
栈:LIFO
接口机制:指定一个类所必须实现的方法
迭代器:实现了hasNext() next()方法的类的对象
嵌套类:可以访问包含它的类的所有数据成员(私有的也行)
链表:Node类(这种类也叫记录)、链接
实现遍历:java.util.Iterator;头文件
Iterable<Item>接口,需要实现iterator()方法
Iterator<Item>接口,需要实现hasNext() next() remove()方法
顺序存储、链式存储
私有嵌套类:只有包含它的类,能够直接访问它的实例变量
内部类:非静态的嵌套类
快速出错迭代器:在迭代器访问期间,禁止添加、删除等操作,使用计数器记录这些操作即可实现。
1.4 算法分析
科学方法:
细致地观察真实世界的特点
根据观察结果,提出假设模型
根据模型预测未来的事件
继续观察,并核实预测的正确性
如此反复,直到观察和预测的一致
科学方法必须是可重现的,假设必须是可证伪的
幂次法则:T(N)=aN^b
数学建模--数学模型分析算法性能
算法设计法:
暴力算法:实现并分析一种简单直接的解法
改进算法:分治、记录法等优化
实验证明新算法更快:性能优化一定要实测,不可猜测
对大常数保持敏感
内循环可能不是真正的决定性因素
大数据,考虑缓存技术
运行时间增长数量级
先写出清晰正确的代码,而后考虑性能优化
不成熟的优化,是所有罪恶之源
1.5 Union-find算法
动态连通性问题
quick find
quick union
加权quick union
第2章 排序 代码
插入排序 稳定 O(n^2) O(1)
选择排序 不稳定 O(n^2) O(1)
希尔排序 不稳定 O(n^1.5) O(1)
快速排序 不稳定 O(nlog(n)) O(log(n))
归并排序 稳定 O(nlog(n)) O(log(n) + n)
堆排序 不稳定 O(nlog(n)) O(1)
优先队列
选举
归并
第3章 查找 代码
顺序查找:链表实现的符号表
顺序查找,属于暴力查找,时间复杂度:O(N)
二分查找:双数组实现的符号表
二分查找只对有序数组有效:有序性、随机访问性,时间复杂度:O(log(N))
二叉查找树:
结合了链表的删除,添加节点的高效性和有序数组二分查找的高效性
时间复杂度:
平均插入:O(log(N))、平均删除:O(log(N))
缺点:最坏性能不能保证,最坏时间复杂度都是O(N),会退化为普通链表
平衡查找树:2-3查找 ---> 红黑树
完美平衡 ---> 保证最坏情况下,时间复杂度仍然是:O(log(N))
2-3查找树和红黑树一一对应。
散列表
hash函数:Java对象默认都有hashcode()方法
碰撞处理:
拉链法散列表:M个符号表 (N/8 <= M <= N/2)
开放地址法:线性探测散列表:一个符号表 (2N <= M <= 8N)
系数矩阵:符号表存储,实现高效的点乘计算。
第4章 图 代码
对象和连接,连接可能有权重和方向
深度优先搜索
栈实现
广度优先搜索
队列实现
最小生成树算法(MST)
Prim:根据已选择的顶点选择最小的边,不断增大树的顶点数目
Kruskal:根据全局最小边,选择合并两棵树,不断减少森林
最短路径算法--最短路径树
Dijkstra:单源最短路径算法,动态规划,更新顶点距离,不能处理负权重边
Bellman-Ford:单源最短路径,可以处理负权重边,环的问题
Floyd-Warshall:任意两点最短路径算法,动态规划
第5章 字符串 代码
字符串排序
低位优先
高位优先
三向快速排序
单词查找树
R向单词查找树
三向单词查找树
子字符串查找
暴力算法
KMP:next()索引实现
BM:从右向左匹配查找
RK:基于散列的字符串查找算法
第6章 背景 代码
基于事件的模拟
主要讲述了一个物理碰撞问题的模拟,抽象模型,系统状态模拟。事件驱动的复杂度,远远优于时间驱动的复杂度
B-树
平衡多向树( <--> AVL),多用于数据库系统的实现,快速查找
后缀数组
最长重复子字符串问题
最大流量问题
图的最短路径
搜索问题
NP问题 <--> P问题
问题转化
NP完全性
理解算法原理,熟悉简单的算法,学会算法式思考。学会问题的规约,掌握基本的问题解决模型,将新问题规约为熟悉的问题,从而得到问题的解。
开始时间:2016-05-06
结束时间:2016-12-21
算法很牛!真的是太牛了!
这算法书籍包含有原理的解释,算法分析,理论的证明,算法实现,特别对于模型的假设和解释非常具体和清晰,一个个数学模型,告诉了我们算法的来源和基本原理,不仅知道了算法基本用法,还知道算法的本质思想,以及可以应用于一些扩展问题。而且书中的实例,都是结合算法的实际应用,进行讲解的,使得算法不再是纯理论的东西,有生动的实例告诉我算法该如何将算法用于解决实际问题。问题领域的概括,告诉我们算法可以应用的广泛领域,即扩展了我们的眼界,也说了这些算法的实用性。
这是一本大部头的书,虽然只有6章,但是足足600多页,今年由于上半年在实习,所以拖拉了很久,到今天才坚持看完这本书,时间虽然花了很多,但是还是很开心,毕竟坚持看完了这本著作,对于数据结构和算法的理解,也有了更深刻的认识,基础功更加扎实了。
这本书虽然和算法导论的风格不一样,但是仍然偏重于算法的证明,证明算法的有效性、正确性、复杂度等。这些确实是算法的本质和核心,表面上对于实际应用作用不大,知道怎么用,就ok了,但是很多实际问题,需要我们规约,不是一眼就能找到解决方案的,这个时候,这些算法原理和分析,就是我们解决新问题的核心 --- 授之于鱼不如授之以渔!
遗憾的是,这本书的习题都没有认真的思考,习题实在是很多,严重影响看书的速度,目前网上也没有完整的习题答案,希望有机会,可以认真的做一遍习题,把所有的答案都敲一遍代码!