经典算法书籍推荐以及算法书排行【算法四库全书】

作者:霞落满天   https://linuxstyle.blog.csdn.net/    https://blog.csdn.net/21aspnet

行文方式:类似《四库全书》截取经典算法书目录和精华篇章

版权说明:本文于2019年5月5日首发于CSDN,若有转载请务必保留版权,为了整理编排选择全文内容花费了2019年一个五一的时间。

文中截图:文中所算书籍截图版权属于出版社,这里只是为了学术研究选了其中几页。

原文链接:https://linuxstyle.blog.csdn.net/article/details/89670703

https://blog.csdn.net/21aspnet/article/details/89670703

引子

算法是计算机科学领域最重要的基石之一。算法是程序的灵魂,只有掌握了算法,才能轻松地驾驭程序开发。

                                                                                                     ---《算法详解(卷1)——算法基础》内容提要

现状

算法已经出现了很多年,目前国内外关于算法的书可谓汗牛充栋,不过精品并不多。算法离不开数据结构,有些讲算法的书并不以算法命名而是叫数据结构,数据结构并不等于算法,数据结构是静态的,而算法是动态的,数据结构是起点和终点,而算法是过程。

算法本身有一定的学习曲线,选一本好书事半功倍,选一本烂书不一定事倍功半,很可能还是看不懂学不会。

网上也不乏一些推荐算法书的,大多数都是说好评,这种推荐用处不大,很多写推荐的自己有没有阅读过都是问题,每本书的行文风格都大不同。

 

 

目的

每个阅读者的看书目的也不同,有人可能就是需要一段可以运行的代码就可以,有人只是想了解下算法的入门知识,还有人要做算法分析研究,所以需要进行比较,选择适合自己的书

本文不是空洞的说教哪一本算法书籍怎么怎么的好,那样是缺乏理论依据的,本文以红黑树为例,实际运行代码,在这个过程以源码能否直接运行还是需要做很多修改才可以运行来进行比较。

 

约定

主要针对欧美经典著作的中文版,如果英文很好建议看看一些论文和外文原著,绝大多数程序员和工程师还是看汉化的。

本文一律以算法代称算法和数据结构。

 

亚马逊和豆瓣

一般看书评大多是看豆瓣的,豆瓣上的还是有一定的客观性,不过依然有很多是只评不看的。

某些电商网站的基本都是好评,这种跟风更是失去了参考意义,不管哪一本书基本90%都是好评甚至是凑数的评价。

最真实的评价是亚马逊英文版的点评。

不过这里又有一个问题汉化所以如果汉化翻译的不好那么一本很好的书可能会逊色很多,甚至节外生枝。

先看最热门的算法书:

其实看封面就知道是那几本了,这几本书其实都已经翻译成中文了,

分别是《算法导论(原书第3版)》《算法 第4版》《算法设计指南 第二版》《算法图解  像小说一样有趣的算法入门书》《数据结构与算法分析 : C语言描述》《算法概论》和豆瓣的排行略有差异,顺序有不同。

截图并不代表本文就完全认同这个排名,不然也就失去写此文的目的,而且豆瓣和亚马逊本身排名就不同也说明问题。

本文就以这几本书为核心,但是又不局限于这几本书,常见的经典的和常见的算法书都会比较。

算法书非常多,很多书“评价”很高,但是真的就一定适合你么?不一定!很多好评是人云亦云的,蝴蝶效应而已,因为很多时候如果别人都说这书好,自己硬是说不好似乎错的是自己?不过也有一些人还是坚持自己的观点,说出某些好评非常多的书的不足,这些人是真正看书的,也是学到东西的人。我相信,一个人只有看出书中的错误才证明他在这个领域有所建树。

 

汉化的问题

1)翻译不准,这个问题是老大难问题,说实话计算机书籍的翻译一般都不是专业翻译,只能词达意,要想信达雅很难,很多时候是阅读者自己水平不够看不懂,然后怪罪于译者,有时候有些英文作者本身语句就很难理解,当然也有些翻译确实又欠缺之处。

2)分卷出版,这个问题其实非常严重,一本书如果不太厚分卷是非常不便于阅读,还有些书分卷之后下卷或者第二卷迟迟不出版,只有半卷的书看起来自然是不完整的,总不至于让人买其他书补充是不是?

3)破坏原书,这个问题最严重,作者自己胡乱夹塞,非要自己加一段“译者注”,本来看着好好的突然来一段“译者注”,要知道译者的水平和原著可是相差万里,这种破坏原书的行为是非常可怕的,就像在一杯美味的咖啡里加入了怪味豆。

 

好书评比的标准

总要有个标准,最好是数据化,不然何以服人?

1.文字

一本书最多的就是文字,语句通顺,容易理解是最重要的,这取决于原始英文的文字水平和翻译后的水平,有些时候不一定是翻译的问题原作就有问题。

2.图表

文字有些时候没有图形更有更富的表现力,特别是演示算法变化。有表格更好,表格在统计学上的卓越表现是文字更难以代替的。

3.深度广度

涵盖常见算法,这是必须的。最起码红黑树要有吧,想想平时程序员关于算法的口头禅是什么,是不是某某大厂面试需要手撕红黑树,所有红黑树自然不能少,而且红黑树出现也有30多年了,对于1970年代的树可以不要求,但是总不能说一本2000年之后的树不写红黑树吧,特别是很多以面试为目的的阅读者,如果买到一本没有写红黑树的书。

更广义的算法广度应该是包含NP问题,动态规划,流网络等内容。

程序员买书无非是解决工作问题或者准备面试,如果太浅显只能当科普了。

关于红黑树参考以下:

为什么Java8中HashMap链表使用红黑树而不是AVL树

https://blog.csdn.net/21aspnet/article/details/88939297

Linux内核的红黑树源码实现以及调用

https://blog.csdn.net/21aspnet/article/details/89641002

https://linuxstyle.blog.csdn.net/article/details/89641002

4.源码

有些书是伪码,有些是C,有些C++,还有Java的,最进一些新书有Python的。

伪码不一定就不好,不能运行的代码不如伪码。

说了这么多总该进入整题了。

 

算法书排行榜

 

1.《算法导论(原书第3版)》

作者:Thomas H.Cormen / Charles E.Leiserson / Ronald L.Rivest / Clifford Stein / 

正如这本书自己的介绍所说在有关算法的书中,在有关算法的书中,有一些叙述非常严谨,但不够全面;另一些涉及了大量的题材,但又缺乏严谨性。本书将严谨性和全面性融为一体,深入讨论各类算法,并着力使这些算法的设计和分析能为各个层次的读者接受。全书各章自成体系,可以作为独立的学习单元;算法以英语和伪代码的形式描述,具备初步程序设计经验的人就能看懂;说明和解释力求浅显易懂,不失深度和数学严谨性。

全书选材经典、内容丰富、结构合理、逻辑清晰,对本科生的数据结构课程和研究生的算法课程都是非常实用的教材,在IT专业人员的职业生涯中,本书也是一本案头必备的参考书或工程实践手册。

本书的作者是麻省理工系任教或者研究生毕业,简介:

Charles E. Leiserson(查尔斯•雷瑟尔森)麻省理工学院计算机科学与电气工程系教授。

Thomas H. Cormen (托马斯•科尔曼) 达特茅斯学院计算机科学系教授、系主任。他分别于1993年、1986年获得麻省理工学院电子工程和计算机科学博士、硕士学位,师从Charles E. Leiserson教授,也就是上面这位的学生。

Ronald L. Rivest (罗纳德•李维斯特)现任麻省理工学院电子工程和计算机科学系。他和Adi Shamir和Len Adleman一起发明了RSA公钥算法,这个算法在信息安全中获得最大的突破,这一成果也使他和Shamir、Adleman一起得到2002年ACM图灵奖。他现在担任国家密码学会的负责人。

Clifford Stein(克利福德•斯坦)哥伦比亚大学计算机科学系和工业工程与运筹学系教授,他还是工业工程与运筹学系的系主任。在加入哥伦比亚大学大学之前,他在达特茅斯学院计算机科学系任教9年。Stein教授拥有MIT硕士和博士学位。

 

本书在内容的广度和深度方面是非常全面,先看本书目录,作者先讲了算法在计算中的作用,算法基础,函数增长。

开篇第一章看似比较平淡,没有怎么显山县水。

第6章开始讲堆排序,第7章整一章讲快速排序可见快排的重要性,其他书是把快速排序作为一种排序方法放在排序章节里。

第10章开始讲基本数据结构,栈和队列,链表,指针这是为了兼顾C/C++。

第11章散列表单独一章,第12章二叉搜索树,红黑树。

高级设计分析技术讲了动态规划,贪心算法(包含哈夫曼编码),摊还分析(包含核算法)

 典型算法问题:线性规划,计算几何学,NP问题,旅行商问题,傅里叶变换。

作者在附录里给出了补充的数学知识。

先看看作者关于分治策略是怎么讲的,分治策略中递归的求解一个问题,在每层递归中应用如下三个步骤:

分解:将问题划分为子问题,子问题的形式与原问题一样,只是规模更小。想一想微服务拆分是不是也就是一种分解思想呢?

解决:递归的求解子问题,如果子问题规模足够小则停止递归,直接求解。想一想微服务拆分服务拆分领域划分到底拆到多微你是不是很多时候没有一个标准?

合并:将子问题的解组合成原问题。想一想微服务是不是要聚合多个结果集。

所以说微服务拆分本身就是一种分治策略,都是一些前人早就总结的理论,没有什么新的。

我们看看这本书对红黑树的讲解,这是本文需要重点和其他算法书对比的地方:

红黑树的定义一共5点说的清清楚楚,和维基百科基本定义是一致的。

https://en.wikipedia.org/wiki/Red%E2%80%93black_tree

光有文字表述肯定是不够的,需要用图形来展示红黑树,结合小字注释看起来更明白。

旋转是红黑树的一个重要特征,只用这样一幅图就轻描淡写的把这个问题演的明明白白。 

算法导论给出的是伪码,我不觉得有什么不好,任何一门编程语言都可以转换为对应的代码,而且他的伪码也不是单纯的代码是给出了足够明确的说明。

再来看看关于B树这一章,作者先讲明B树是为磁盘或其他辅助存储设备设计的平衡搜索树,B树类似红黑树,但是又不同。

作者随后讲述了为什么针对磁盘设计的数据结构不同于内存,感兴趣可以看看原书。

相信大家基本看懂了,当然这里并不是原书,只是用来比较算法书的优劣,学习还是需要自己去看原书的。

 

2.《算法(第4版)》

作者:Robert Sedgewick / Kevin Wayne

因为这本书流传甚广,所以本文对于这本书花了很多笔墨,也为了快速让读者先睹为快,直接看我的总结。

总结:如果你想学习算法理论,这不是一本好书,如果你只是要代码库,可以直接从教参网站下载,但是不能直接用,会依赖私有库,需要自己改。 选择此书需要慎重,建议一定要看完本文对此书的分析,你就知道适合不适合你。

这本书作者是奇威克 (Robert Sedgewick) 和韦恩 (Kevin Wayne),其中Robert Sedgewick是斯坦福大学博士,导师为Donald E. Knuth。Donald E. Knuth是图灵机获得者,他有传世著作《计算机程序设计艺术》。Donald E. Knuth的学生很多,导师是导师,学生是学生,我觉得因为导师著名,学生就著名不成立。

这本书之前是分为两本出版分别是《算法:C语言实现(第1-4部分)基础知识、数据结构、排序及搜索》和《算法:C语言实现(第5部分)图算法》,在那个版本里作者就Robert Sedgewick一个人。那一版是C语言的,对于学C/C++的可以看看。新版第4版是java语言的,估计作者是为了迎合市场。

先看全书内容,基本的数据结构都包含了,但是内容是明显比《算法导论》单薄许多,如果不说这本书在豆瓣9.4分,亚马逊上几乎是和《算法导论》并列的书你很难想象这本书是怎么出名的。

全书600多页基本是停留在数据结构,图,最短路径讲到了。高级一点的内容对于算法分析和设计,NP问题,动态规划等没有涉及,所以这本书在内容上的广度和深度上是不够的。但是如果那些不是你需要研究的,那部分缺失的内容自然就不重要了。

我们直接看红黑树这一节,说实话关于红黑树的定义莫名其妙,红链接和黑链接,你看得懂么?为什么就不能12345列出来。

感觉作者的表述非常的绕。红黑树右边的这幅图对于一个从没看过红黑树的人绝对是一脸的懵!这本书最大的问题就是比较啰嗦。

对比《算法导论》红黑节点是不能一目了然的,而作者给出的变通办法是用彩页,其实是完全没必要的。 

 

再看看代码实现,不是伪码,是Java的,不过代码不够清晰简洁,最主要的是从作者提供的网站下载的代码不能直接用,要改。

作者提供了一个在线教参网站和github提供了代码库,书中提及的算法大都有源码实现,对于只需要源码的人可以直接下载,网站上还有些精简版资源。

https://algs4.cs.princeton.edu/

Robert Sedgewick和Kevin Wayne的教科书 Algorithms,4th Edition调查了当今使用的最重要的算法和数据结构。 我们通过检查其对科学,工程和行业应用的影响来激励我们解决的每个算法。该教科书分为六章:

  • 第1章:基础知识 介绍了比较算法和进行预测的科学和工程基础。它还包括我们的编程模型。
  • 第2章:排序 考虑了几种经典排序算法,包括插入排序,合并排序和快速排序。它还具有优先级队列的二进制堆实现。
  • 第3章:搜索 描述了几种经典的符号表实现,包括二叉搜索树,红黑树和哈希表。
  • 第4章:图形 调查最重要的图形处理问题,包括深度优先搜索,广度优先搜索,最小生成树和最短路径。
  • 第5章:字符串 研究字符串处理的专用算法,包括基数排序,子字符串搜索,尝试,正则表达式和数据压缩。
  • 第6章:上下文 强调了与系统编程,科学计算,商业应用,运筹学和难以处理的联系。
  • Java代码。本教科书中的算法和客户端[ algs4 · github ]。

 https://algs4.cs.princeton.edu/code/

https://github.com/kevin-wayne/algs4

公共存储库 包含Robert Sedgewick和Kevin Wayne 在教科书Algorithms,4th Edition中的算法和客户端 的Java 源代码。这是官方版本 - 作者积极维护和更新。这些计划是在包中组织的。如果只需要类文件(而不是源代码),则可以使用 algs4.jar。 edu.princeton.cs.algs4

这里把一些常用算法列举出来。

2排序
2.1Insertion.java插入排序
-InsertionX.java插入排序(优化)
-BinaryInsertion.java二进制插入排序
2.2Selection.java选择排序
2.3Shell.java希尔排序
2.4Merge.java自上而下的合并
-MergeBU.java自下而上的合并
-MergeX.java优化的合并
-Inversions.java反转次数
2.5Quick.java快速排序
-Quick3way.java快速排序,具有3向分区
-QuickX.java优化的双向快速排序
-QuickBentleyMcIlroy.java优化的3向快速排序
-TopM.java优先队列客户端
2.6MaxPQ.java最大堆优先级队列
-MinPQ.java最小堆优先级队列
-IndexMinPQ.javaindex min heap优先级队列
-IndexMaxPQ.javaindex最大堆优先级队列
-Multiway.java多路合并
2.7Heap.java堆排序
3搜索
-FrequencyCounter.java频率计数器
3.1SequentialSearchST.java顺序搜索
3.2BinarySearchST.java二分搜索
3.3BST.java二叉搜索树
3.4RedBlackBST.java红黑树
3.5SeparateChainingHashST.java单独的链接哈希表
3.6LinearProbingHashST.java线性探测哈希表
-ST.java有序符号表
-SET.java有序集
-DeDup.java删除重复项
-WhiteFilter.java白名单过滤器
-BlackFilter.java黑名单过滤器
-LookupCSV.java字典查找
-LookupIndex.java指数和倒排指数
-FileIndex.java文件索引
-SparseVector.java稀疏的矢量
4
-Graph.java无向图
-GraphGenerator.java生成随机图
-DepthFirstSearch.java深度优先搜索图表
-NonrecursiveDFS.java图中的DFS(非递归)
4.1DepthFirstPaths.java图中的路径(DFS)
4.2BreadthFirstPaths.java图中的路径(BFS)
4.3CC.java连接的图形组件
-Bipartite.java二分或奇数周期(DFS)
-BipartiteX.java二分或奇数周期(BFS)
-Cycle.java在图表中循环
-EulerianCycle.java欧拉循环图
-EulerianPath.java在图中的欧拉路径
-SymbolGraph.java符号图
-DegreesOfSeparation.java分离度
-Digraph.java有向图
-DigraphGenerator.java生成随机有向图
4.4DirectedDFS.java深度优先搜索有向图
-NonrecursiveDirectedDFS.java有向图中的DFS(非递归)
-DepthFirstDirectedPaths.java有向图中的路径(DFS)
-BreadthFirstDirectedPaths.java有向图中的路径(BFS)
-DirectedCycle.java在有向图中循环
-DirectedCycleX.java在有向图中循环(非递归)
-DirectedEulerianCycle.java欧拉循环在有向图
-DirectedEulerianPath.java在有向图的欧拉路径
-DepthFirstOrder.java有向图中的深度优先顺序
4.5Topological.javaDAG中的拓扑顺序
-TopologicalX.java拓扑顺序(非递归)
-TransitiveClosure.java传递闭包
-SymbolDigraph.java符号有向图
4.6KosarajuSharirSCC.java强大的组成部分(Kosaraju-Sharir)
-TarjanSCC.java强大的组件(Tarjan)
-GabowSCC.java强大的组成部分(Gabow)
-EdgeWeightedGraph.java边加权图
-Edge.java加权边缘
-LazyPrimMST.javaMST(懒惰的Prim)
4.7PrimMST.javaMST(Prim)
4.8KruskalMST.javaMST(Kruskal)
-BoruvkaMST.javaMST(Boruvka)
-EdgeWeightedDigraph.java边加权有向图
-DirectedEdge.java加权,有向边
4.9DijkstraSP.java最短的路径(Dijkstra)
-DijkstraUndirectedSP.java无向的最短路径(Dijkstra)
-DijkstraAllPairsSP.java全对最短路径
4.10AcyclicSP.javaDAG中的最短路径
-AcyclicLP.javaDAG中最长的路径
-CPM.java关键路径法
4.11BellmanFordSP.java最短的路径(贝尔曼 - 福特)
-EdgeWeightedDirectedCycle.java在边加权有向图中循环
-Arbitrage.java套利检测
-FloydWarshall.java全对最短路径(密集)
-AdjMatrixEdgeWeightedDigraph.java边加权图(密集)

 以红黑树为例,下载的代码不能直接运行,需要集成作者的私有库标准库!

使用标准库。

文件stdlib.jar将所有标准库捆绑到一个文件中。有许多方法可以访问这些库:

https://introcs.cs.princeton.edu/java/stdlib/

 以作者写的红黑树为例不能直接运行,需要做一些改进,剥离私有库才可以用。

https://algs4.cs.princeton.edu/33balanced/RedBlackBST.java.html

 

3.《算法设计指南 第二版》

作者:Steven Skiena

这本书由清华大学在2017年出版了,按说到今天也有2年左右时间,不过评语在豆瓣和亚马逊是天壤之别。

很多中国读者估计不知道还有这么一本算法好书,这书影响不大是有些客观原因。 

1.本科教学版,直接看上图,估计看到这几个字很多人就不想买了,这让我们想起了大学时代很多本科教学版,对于很多研究生来说估计看到这几个字直接拒绝的,但是平心而论,本书的水平非常高,肯定是超越本科水平。

2.孤军奋战,还是看上图,现在计算机书基本是机械工业出版社经典教材黑皮书,人民邮电的动物书,电子工业的那种绿皮书,,清华大学也有一套黑皮书。这四大出版社涵盖了绝大多数计算机经典书籍,也有好书不是上述封面包装系列,不过一般读者看到这三大出版社都会认可的。而本书就是不在清华黑皮书系列里,导致在书架和网站位置不突出,就无人关注。

3.内容不全,目前这本只是第1卷,没有出后续版本,内容肯定是不全的。

4.多余的译者注,有人说译者喜欢加一点译者注,我觉得这不是什么大问题,你不看就是。

这本书的总结是:书是好书,就是因为种种原因导致出现今天这样的结局,只能说可惜。这本书你可以作为其他书的补充,也可以做比较好的入门书。

这本书的内容就300多页,红黑树AVL树都没有深入讲解,只讲了基本的数据结构。

对于算法复杂度有些模糊可以看看第二章,作者吧这个单独一章可以看出作者的用心。

数据结构和查找排序这块都讲的非常少,但是不代表简单。 

看到动态规划,NP问题是否有点意外。 

翻译也是很精彩的,下面截取一些精彩片段,其实全书精彩片段几乎遍地都是。

作者关于算法的定义:何谓算法?算法是完成某项特定任务的具体步骤,算法更是藏于程序背后的思想。

一个算法要想让人关注,它一定要能解决一个有着清楚而且准确叙述的一般性问题。 

 作者把数据结构分为紧接和链接型是非常简洁的。

可以说读起来是非常上口,作者总是妙笔生花,很精彩的一本书,你要是喜欢可以看看,不过看完估计你还是意犹未尽。 

 

4.《数据结构与算法分析》

作者:Mark Allen Weiss

这本书的分析太长了,先总结:本书内容深度不像算法导论等算法分析的书那些深,广度上也不逊于算法导论,书的厚度是算法导论的一半不到一点。内容非常精炼,没有废话。本书有源码可以直接运行,而且还分了多语言

看到此图你是否有点震惊!作者居然用C/C++/Java三种语言同时写一本书,而且还是分别成册。

《数据结构与算法分析——C语言描述(原书第2版)》机械工业出版社 冯舜玺译,英文版是1997年,中文是2003年;

数据结构与算法分析——C语言描述(原书第2版)典藏版》 机械工业出版社 冯舜玺译,典藏版其实还是老版,中文是2019年。

《数据结构与算法分析C++描述(第三版)》人民邮电出版社,这个版本是另一拨人翻译的,这个版本已经卖不到了。

《数据结构与算法分析C++描述(第四版)》电子工业出版社,又由C语言版的冯舜玺译,英文版是2014年,中文是2016年;

《数据结构与算法分析:java语言描述(原书第3版)》机械工业出版社 冯舜玺译,英文版是2012年,中文是2016年;

作者不同语言的书差别不大,没必要都看,只是代码不同,根据自己需要的编程语言选择合适的版本即可。

需要说的是Mark Allen Weiss的书评价还是非常高的,原书曾被评为20世纪顶尖的30部计算机著作之一,作者Mark Allen Weiss在数据结构和算法分析方面卓有建树,他的数据结构和算法分析的著作尤其畅销,并受到广泛好评。已被世界500余所大学用作教材。在书中,作者更加精炼并强化了他对算法和数据结构方面创新的处理方法。着重阐述了抽象数据类型的概念,并对算法的效率、性能和运行时间进行了分析。

 

这本书既然是分编程语言可见不同语言自然是有侧重点。

以C++版为例先讲C++类和指针模板和STL中的vector和list。

以java版为例,java的数据结构基础知识泛型,抽象数据类型,表ADT,Java CollectionsAPI中的 Collections接口,Iterator接口,List接口,ArrayList类。

核心数据结构树 分为二叉树及其实现,AVL树,伸展树,B树;散列是单独一章,可见作者对其重要性的侧重,这一章讲了分离链接法,线性探测法,再散列,完美散列,布谷鸟散列,跳房子散列。

红黑树是放在第12章的,不要错过。

看看作者对红黑树是怎么讲的

经典就是经典,这里也是很清晰的1234,红黑树的高度最多是2log(N+1),对红黑树的最坏情形下花费O(logN)时间,作者一针见血的点出红黑树和AVL树相比。红黑树的配图也是很清楚没有绕来绕去。作者经验是非常丰富,用词准确不说废话。

红黑树的插入作者先说了自底向上的插入,分两种情形单旋转和双旋转,图形也很简洁。

作者给出了这本书的源码不管是C/C++/Java,不过仅限于教师可以在网站下载,机械工业出版社网站是有的,如果不是教师想得到可以利用百度谷歌等搜素引擎搜素,也可以找到的。为了方便大家本人已经上传了:

https://download.csdn.net/download/21aspnet/11157988

书中的源码选取了核心部分类的初始化构造函数里定义红黑树的节点:

如果你想要完整的红黑树代码可以自己网络寻找,为了方便读者这里贴出作者写的红黑树源码RedBlackTree.class

package com.algs.www;// RedBlackTree class
//
// CONSTRUCTION: with no parameters
//
// ******************PUBLIC OPERATIONS*********************
// void insert( x )       --> Insert x
// void remove( x )       --> Remove x (unimplemented)
// boolean contains( x )  --> Return true if x is found
// Comparable findMin( )  --> Return smallest item
// Comparable findMax( )  --> Return largest item
// boolean isEmpty( )     --> Return true if empty; else false
// void makeEmpty( )      --> Remove all items
// void printTree( )      --> Print all items
// ******************ERRORS********************************
// Throws UnderflowException as appropriate

/**
 * Implements a red-black tree.
 * Note that all "matching" is based on the compareTo method.
 * @author Mark Allen Weiss
 */
public class RedBlackTree<AnyType extends Comparable<? super AnyType>>
{
    /**
     * Construct the tree.
     */
    public RedBlackTree( )
    {
        nullNode = new RedBlackNode<>( null );
        nullNode.left = nullNode.right = nullNode;
        header      = new RedBlackNode<>( null );
        header.left = header.right = nullNode;
    }

    /**
     * Compare item and t.element, using compareTo, with
     * caveat that if t is header, then item is always larger.
     * This routine is called if is possible that t is header.
     * If it is not possible for t to be header, use compareTo directly.
     */
    private int compare( AnyType item, RedBlackNode<AnyType> t )
    {
        if( t == header )
            return 1;
        else
            return item.compareTo( t.element );    
    }
    
    /**
     * Insert into the tree.
     * @param item the item to insert.
     */
    public void insert( AnyType item )
    {
        current = parent = grand = header;
        nullNode.element = item;

        while( compare( item, current ) != 0 )
        {
            great = grand; grand = parent; parent = current;
            current = compare( item, current ) < 0 ?
                         current.left : current.right;

                // Check if two red children; fix if so
            if( current.left.color == RED && current.right.color == RED )
                 handleReorient( item );
        }

            // Insertion fails if already present
        if( current != nullNode )
            return;
        current = new RedBlackNode<>( item, nullNode, nullNode );

            // Attach to parent
        if( compare( item, parent ) < 0 )
            parent.left = current;
        else
            parent.right = current;
        handleReorient( item );
    }

    /**
     * Remove from the tree.
     * @param x the item to remove.
     * @throws UnsupportedOperationException if called.
     */
    public void remove( AnyType x )
    {
        throw new UnsupportedOperationException( );
    }

    /**
     * Find the smallest item  the tree.
     * @return the smallest item or throw UnderflowExcepton if empty.
     */
    public AnyType findMin( )
    {
        if( isEmpty( ) )
            throw new UnderflowException( );

        RedBlackNode<AnyType> itr = header.right;

        while( itr.left != nullNode )
            itr = itr.left;

        return itr.element;
    }

    /**
     * Find the largest item in the tree.
     * @return the largest item or throw UnderflowExcepton if empty.
     */
    public AnyType findMax( )
    {
        if( isEmpty( ) )
            throw new UnderflowException( );

        RedBlackNode<AnyType> itr = header.right;

        while( itr.right != nullNode )
            itr = itr.right;

        return itr.element;
    }

    /**
     * Find an item in the tree.
     * @param x the item to search for.
     * @return true if x is found; otherwise false.
     */
    public boolean contains( AnyType x )
    {
        nullNode.element = x;
        current = header.right;

        for( ; ; )
        {
            if( x.compareTo( current.element ) < 0 )
                current = current.left;
            else if( x.compareTo( current.element ) > 0 ) 
                current = current.right;
            else if( current != nullNode )
                return true;
            else
                return false;
        }
    }

    /**
     * Make the tree logically empty.
     */
    public void makeEmpty( )
    {
        header.right = nullNode;
    }

    /**
     * Print the tree contents in sorted order.
     */
    public void printTree( )
    {
        if( isEmpty( ) )
            System.out.println( "Empty tree" );
        else
            printTree( header.right );
    }
    
    /**
     * Internal method to print a subtree in sorted order.
     * @param t the node that roots the subtree.
     */
    private void printTree( RedBlackNode<AnyType> t )
    {
        if( t != nullNode )
        {
            printTree( t.left );
            System.out.println( t.element );
            printTree( t.right );
        }
    }
     
    /**
     * Test if the tree is logically empty.
     * @return true if empty, false otherwise.
     */
    public boolean isEmpty( )
    {
        return header.right == nullNode;
    }

    /**
     * Internal routine that is called during an insertion
     * if a node has two red children. Performs flip and rotations.
     * @param item the item being inserted.
     */
    private void handleReorient( AnyType item )
    {
            // Do the color flip
        current.color = RED;
        current.left.color = BLACK;
        current.right.color = BLACK;

        if( parent.color == RED )   // Have to rotate
        {
            grand.color = RED;
            if( ( compare( item, grand ) < 0 ) !=
                ( compare( item, parent ) < 0 ) )
                parent = rotate( item, grand );  // Start dbl rotate
            current = rotate( item, great );
            current.color = BLACK;
        }
        header.right.color = BLACK; // Make root black
    }

    /**
     * Internal routine that performs a single or double rotation.
     * Because the result is attached to the parent, there are four cases.
     * Called by handleReorient.
     * @param item the item in handleReorient.
     * @param parent the parent of the root of the rotated subtree.
     * @return the root of the rotated subtree.
     */
    private RedBlackNode<AnyType> rotate( AnyType item, RedBlackNode<AnyType> parent )
    {
        if( compare( item, parent ) < 0 )
            return parent.left = compare( item, parent.left ) < 0 ?
                rotateWithLeftChild( parent.left )  :  // LL
                rotateWithRightChild( parent.left ) ;  // LR
        else
            return parent.right = compare( item, parent.right ) < 0 ?
                rotateWithLeftChild( parent.right ) :  // RL
                rotateWithRightChild( parent.right );  // RR
    }

    /**
     * Rotate binary tree node with left child.
     */
    private RedBlackNode<AnyType> rotateWithLeftChild( RedBlackNode<AnyType> k2 )
    {
        RedBlackNode<AnyType> k1 = k2.left;
        k2.left = k1.right;
        k1.right = k2;
        return k1;
    }

    /**
     * Rotate binary tree node with right child.
     */
    private RedBlackNode<AnyType> rotateWithRightChild( RedBlackNode<AnyType> k1 )
    {
        RedBlackNode<AnyType> k2 = k1.right;
        k1.right = k2.left;
        k2.left = k1;
        return k2;
    }

    private static class RedBlackNode<AnyType>
    {
            // Constructors
        RedBlackNode( AnyType theElement )
        {
            this( theElement, null, null );
        }

        RedBlackNode( AnyType theElement, RedBlackNode<AnyType> lt, RedBlackNode<AnyType> rt )
        {
            element  = theElement;
            left     = lt;
            right    = rt;
            color    = RedBlackTree.BLACK;
        }

        AnyType               element;    // The data in the node
        RedBlackNode<AnyType> left;       // Left child
        RedBlackNode<AnyType> right;      // Right child
        int                   color;      // Color
    }
    
    private RedBlackNode<AnyType> header;
    private RedBlackNode<AnyType> nullNode;

    private static final int BLACK = 1;    // BLACK must be 1
    private static final int RED   = 0;

        // Used in insert routine and its helpers
    private RedBlackNode<AnyType> current;
    private RedBlackNode<AnyType> parent;
    private RedBlackNode<AnyType> grand;
    private RedBlackNode<AnyType> great;


        // Test program
    public static void main( String [ ] args )
    {
        RedBlackTree<Integer> t = new RedBlackTree<>( );
        final int NUMS = 400000;
        final int GAP  =  35461;

        System.out.println( "Checking... (no more output means success)" );

        for( int i = GAP; i != 0; i = ( i + GAP ) % NUMS )
            t.insert( i );

        if( t.findMin( ) != 1 || t.findMax( ) != NUMS - 1 )
            System.out.println( "FindMin or FindMax error!" );

        for( int i = 1; i < NUMS; i++ )
             if( !t.contains( i ) )
                 System.out.println( "Find error1!" );
    }
}

这个代码相比《算法4》比较好,没有依赖私有库,只依赖了一个UnderflowException:

/**
 * Exception class for access in empty containers
 * such as stacks, queues, and priority queues.
 * @author Mark Allen Weiss
 */
public class UnderflowException extends RuntimeException
{
}

这个代码可以运行的:

 

 5.《算法图解  像小说一样有趣的算法入门书》

作者:Aditya Bhargava

这本书不想前面所列的几本书比较老,这本书在最近纪年才出现的,出现后评价非常高,可见此书似乎小视。

按照内容提要本书示例丰富,图文并茂,以简明易懂的方式阐释了算法,旨在帮助程序员在日常项目中更好地利用
算法为软件开发助力。前三章介绍算法基础,包括二分查找、大O 表示法、两种基本的数据结构以及递归等。余下的篇幅将主要介绍应用广泛的算法,具体内容包括:面对具体问题时的解决技巧,比如何时采用贪婪算法或动态规划;散列表的应用;图算法;K 最近邻算法。本书适合所有程序员、计算机专业相关师生以及对算法感兴趣的读者。

再看看作者说他为什么写此书,原因就是因为爱好而踏入了编程殿堂。随着学到的知识也越来越多,但对算法却始终没搞明白。作者买了一本算法书,但那本书深奥难懂,看了几周后就放弃了。直到遇到一位优秀的算法教授后,才认识到这些概念是多么地简单而优雅。

另一点是几年前,撰写了第一篇图解式博文,对图解式写作风格钟爱有加。

所以从以上可以看出作者写书的目的是因为其他算法书难懂,于是作者就以图解的方式写了这样一本新书。

先看目录吧,很难想象一本200页的书作者居然涵盖了这么多内容,连NP问题,动态规划,K临近算法都有。

 

不过由于全书只有200页,内容深度肯定不会太多。红黑树AVL树都没有。

不过作者对于其他书没有的内容,比如机器学习OCR,推荐系统,对于大数据相关的mapreduce相关的分布式算法,映射函数,归并函数也有涉及。

找不到红黑树只能看到第11章的树。

 

看到这里你是不是很失望,对于作者所谓的图解其实也不是很高端,我开始以为的图解是画出非常复杂又好理解的图,而作者这种图解其实也只是在其他算法书基础上使用了简洁的手绘风格而已,本身没有新的创造。

再看一个推荐算法的特征抽取

至此读者应该大致明白了,这本书连入门都算不上,只能算科普。

所以本书的定位完全就是休闲消遣,实用性不大,估计很多人是被本书书名吸引来的。 

 

6.《算法概论》

作者: Sanjoy Dasgupta / Christos Papadimitriou / Umesh Vazirani

 本书涵盖了绝大多数算法设计中的常用技术。在表达每一种技术时,阐述它的应用背景,强调每个算法运转背后的简洁数学思想,注意运用与其他技术类比的方法来说明它的特征,并提供了大量相应实际问题的例子。同时也注重了对每一种算法的复杂性分析。全书共10章,从基本的数字算法人手,先后介绍了分治、图的遍历、贪心算法、动态规划、线性规划等技术,对NP完全问题进行厂基本而清晰的阐述,对随机算法、近似算法和量子算法也花费了一定的笔墨。

作者简介:Sanjoy Dasgupta于2002年在加州大学伯克利分校获得计算机科学专业的博士学位。他是AT&T实验室的高级技术人员。他的工作重点是研究数据挖掘的算法,对业务数据的语音识别和分析的应用。他在多维数据的统计分析的开发算法领域获得很重要的研究成果。

看目录,本书和前面几本书相比没有基础数据结构的介绍,直接讲算法思想,分治算法,贪心算法,动态规划,线性规划再到NP问题都是算法设计的领域。

 从目录看出来这本不是一本基础的算法书,属于算法设计类的书,内容是又一定的深度的。

第4章 图中的距离,首先讲深度优先搜索DFS可以明确给出从起始点到所有目标顶点的路径,然而这些路径并不是最经济的,所有引出本章要讨论的寻找图中最短路径的算法。两点之间的距离是两者之间最短路径的长度,然后作者给出一个绳子和球的模型来测量这个问题。

从上面的截图看出作者给出的非常的图示清晰易懂,也不复杂。这本书非常厚,图多是一个原因。

优先队列的实现,有几种方式数组,二分堆,D堆,Fibonacci堆。

Dijkstra算法算法的运行时间是严重依赖于优先队列的所用的实现方法,作者给出了一张表做对比。

再看看关于动态规划这一章作者关于旅行商问题的讲解,旅行商问题也就是TSP问题。

旅行商问题不明白可以可以参考:https://zh.wikipedia.org/wiki/%E6%97%85%E8%A1%8C%E6%8E%A8%E9%94%80%E5%91%98%E9%97%AE%E9%A2%98

旅行商问题(最短路径问题)(英语:travelling salesman problemTSP)是这样一个问题:给定一系列城市和每对城市之间的距离,求解访问每一座城市一次并回到起始城市的最短回路。它是组合优化中的一个NP困难问题,在运筹学和理论计算机科学中非常重要。

是不是和前面的求最短路径是否很相似,都是画出一幅精炼的图示。

动态规划给出了一个相对而言快得多的解答,虽然它不是多项式时间的。

对于TSP子问题意味着部分解,而最显而易见的部分解是旅行路线最初的部分,后面作者给出了子问题的求解。

上图是代码的伪码算法以及总的运行时间。

最后在书的附录里作者给出了各章的历史背景和深入学习的资料,例如对于NP问题,NP完全性的概念最初见于Steve Cook的论文中,Dick Karp列出了23个NP问题以及本书第8章所有NP完全性已经得到证明的问题。

总结:这是一本有深度有厚度的算法分析书,如果你只想知道快速排序,红黑树之类的是什么这本书不适合你。 如果你想要直接可以运行的代码这本书更不适合你。

 

7.《计算机程序设计艺术》

作者:Donald E.Knuath(高徳纳)

这套书一共出了4卷,前三卷是国防工业出版社出版,第4卷是机械工业出版社出版,第4卷又分为01234一共五本书,译者都是苏运霖老师。

《计算机程序设计艺术(第1卷)基本算法》国防工业出版社.英文1997年,2002年出版

《计算机程序设计艺术(第2卷)半数值算法》国防工业出版社.英文1998年,中文2002年出版

《计算机程序设计艺术(第3卷)排序与查找》国防工业出版社.英文1998年,2002年出版

《计算机程序设计艺术:第4卷 第4册(双语版)生成所有树组合生成的历史》机械工业出版社.2007年出版

作者简介

Donald.E.Knuth(中文名高德纳)是算法和程序设计技术的先驱者,他当前正全神贯注于完成其关于计算机科学的史诗性的七卷集。这一伟大工程在1962年他还是加利福尼亚理工学院的研究生时就开始了。Knuth教授获得了许多奖项和荣誉,包括图灵奖(ACM Turing Award),注意人家1974年就获得了图灵奖。

访问Knuth教授的个人主页:https://www-cs-faculty.stanford.edu/~knuth/

谈到算法书是无论如何也不能回避这本书,《计算机程序设计的艺术》被《美国科学家》杂志列为20世纪最重要的12本物理科学类专著之一,与爱因斯坦《相对论》、狄拉克《量子力学》、理查·费曼《量子电动力学》等经典比肩而立。

不过但是又很少有人看,原因是成书时间太久,数学公式论证很多,不够"实用"。

以第3卷为例,从目录来看属于现在看起来比较基本的数据结构,红黑树肯定不会有。

第6章查找讲了二叉平衡树,作者先说俄国数学家对维持一棵好查找树的问题。 

 后面基本是求证和各种公式推导,定理证明。

一棵平衡树的查找路径长度绝不会比最优树长45%以上,然后给出定理,具有内节点的一棵平衡树的高度区间

总结:这本书肯定是一本好书但是不适合绝大多数人,如果你想了解算法的历史和一些数据结构算法的推导过程可以看看。

对于本科学生和工作年限不长的工作人员这本书是不适合的,一般用不上,本书分成很多分卷也不便于阅读特别是第4卷基本是作者想到什么写什么然后马上出版一本小册子。

 

8.《数据结构基础》《计算机算法》《数据结构、算法与应用》

作者:霍罗维兹 (Ellis Horowitz) / 萨尼 (Sartaj Sahni) / 拉贾瑟·克雷恩 (Sanguthevar Rajasekeran)

这套书版本比较复杂,数据结构C语言版的作者一共三个人,数据结构C++版的第三个作者不一样,这个版本差异不太大就是编程语言不同。

Sartaj Sahni又自己单独写了本C++的,结构版本差异完全是另一本书。

然后C语言的2个人新加一个人又出了一本叫计算机算法的的,结构版本和C语言的也差距很大。

《数据结构(C语言版)》原书名: Fundamentals of Data Structures in C,作者:Ellis Horowitz,Sartaj Sahni,Susan Anderson-Freed 译者: 李建中 张岩 李治军  出版社:机械工业出版社.2006年

《数据结构(C语言版)(第2版)》原书名: Fundamentals of Data Structures in C,作者:Ellis Horowitz,Sartaj Sahni,Susan Anderson-Freed  译者:朱仲涛     出版社:清华大学出版社.2009年

说明:第二版和第一版差别不大,不过出版社和翻译的都换了。

《数据结构基础(C语言版)(第2版)》是最经典数据结构教材的最新版本,国内外大多数的同类教材都是以《数据结构基础(C语言版)(第2版)》为蓝本编写而来的。《数据结构基础(C语言版)(第2版)》用C作为描述语言,书中详细讨论了栈、队列、链表以及查找结构、高级树结构等功能,对裴波那契堆、伸展树、红黑树、2-3树、2-3-4树、二项堆、最小-最大堆、双端堆等新的数据结构进行了有效分析,以及构成所有软件基础的排序散列技术。此外,《数据结构基础(C语言版)(第2版)》还介绍了各种高级或特殊数据结构,如优先级队列、高效二叉查找树、多路查找树等。《数据结构基础(C语言版)(第2版)》对大多数算法都给出了计算时间在最优、最差情形下的复杂度分析。

教材网站:https://www.cise.ufl.edu/~sahni/fdsc2ed/

《数据结构基础(C++语言版)(第2版)》原书名: Fundamentals of Data Structures in C++ 2nd Edition 作者:Ellis Horowitz,Sartaj Sahni,Dinesh Mehta  译者:张力     出版社:清华大学出版社.2009年

《数据结构、算法与应用(C++语言描述)(原书第2版)》原书名: Data Structures, Algorithms, And Applications In C++ 2nd Edition

这本书是Sartaj Sahni一个人写的,风格和数据结构基础(C++语言版)差不多,多了一些算法分析的内容。

《计算机算法(C++语言描述)(第2版)》原书名: Computer Algorithms 2nd Edition  Computer Algorithms 2nd Edition 作者:Ellis Horowitz,Sartaj Sahni,Sanguthevar Rajasekaran     出版社:清华大学出版社.2015年

看看数据结构的目录:

  

这本书作者章节分的很细很实用,以第7章排序为例,讲了插入排序, 快速排序,排序最快有多快,归并排序 ,堆排序 ,多关键字排序 ,链表排序和索引表排序 , 内部排序,外部排序 。

这本书讲的树是很全面的,第9章优先队列的左倾树,第10章高效二叉查找树最优二叉查找树,AVL树,红黑树,Splay树,第11章多路查找树,m-路查找树,B树,B+树。第12章 数字查找结构的数字查找树,二路Trie树,Patricia树,多路Trie树,后缀树。

整体数据结构内容是很完整的,非常全面,你想看的树都有。

下面以红黑树为例,看看内容风格结构。关于红黑树作者给出了两种不同定义的红黑树,这个是有别于其他树的。

一种是每个空指针都用哟个外部节点替换,第二种是如果为任意节点指向子节点的指针上色,有另一种等价定义。

同时作者指出入宫知道指针颜色就可以导出节点颜色,反之也可以。

关于红黑树作者画出了一棵简洁的图,给出引理并给与证明。 

引理 令从根到外部节点的路径长度是路径上指针的数目,如果P和Q是一棵红黑树中从根到外部节点的两条路径,

那么length(P)≤2length(Q)。

本书作者的图画的简洁,这样的例子比比皆是。

例如B+树作者画了一棵三阶B+树,一棵M阶B+树性质:

所有数据节点在一层,数据节点只包含数据元素。

索引节点构成一棵M阶B+树。

关于B+树的查找提供两种查找,一种是精确匹配查找,一种是范围查找。

类似上图中B+树查找算法的高层描述这本书的代码量不多。

这本书的C++版本--《数据结构基础(C++语言版)(第2版)》就不说了,整体差不多。

《数据结构、算法与应用(C++语言描述)(原书第2版)》这本书第三部分多了算法设计方法:

贪婪算法 分治,动态规划,回溯法和分支定界解背包问题,旅行商问题,电路板排列。

 

9.《算法设计与分析基础》 

作者: Anany levitin 

作者基于丰富的教学经验,开发了一套全新的算法分类方法。该分类法站在通用问题求解策略的高度,对现有大多数算法准确分类,从而引领读者沿着一条清晰、一致、连贯的思路来探索算法设计与分析这一迷人领域。 

《算法设计与分析基础 第2版》作者: Anany levitin.清华大学出版社2007年出版.翻译: 潘彦。

《算法设计与分析基础 第3版》作者: Anany levitin.清华大学出版社2015年出版.翻译: 潘彦。

这本书不是从数据结构开始讲起,类似算法概论一类书讲算法设计思想,与算法导论等书不同。

这本书最大的特色就是作者把各种算法进行了归类总结分为

蛮力法:选择排序,冒泡排序,顺序查找,蛮力字符串匹配,最近对和凸包问题,穷举查找(旅行商问题,背包问题,分配问题),深度优先查找和广度优先查找。

分治法:合并排序,快速排序,二叉树遍历,大整数乘法和Strassen矩阵乘法,用分治法解最近对问题和凸包问题

减治法:插入排序,拓扑排序,生成组合对象的算法,减常因子算法(折半查找,假币问题,俄式乘法,约瑟夫斯问题),减可变规模算法(计算中值和选择问题,插值查找,二叉查找树的查找和插入)

变治法:预排序,高斯消去法,平衡查找树(AVL树,2-3树),堆排序,霍纳法则和二进制幂,问题化简(求最小公倍数,计算图中的路径数量,优化问题的化简,线性规划,简化为图问题)

时空权衡:计数排序,散列法,B树

动态规划:背包问题和记忆功能,最优二叉查找树,Warshall算法和计算完全最短路径的Floyd算法

贪婪技术:Prim算法,Kruskal算法,Diikstra算法,哈夫曼树及编码

迭代改进:单纯形法,最大流量问题。

第5章,分治法,合并排序,作者说合并排序是成功应用分治技术的一个完美例子。

对一个需要排序的数组合并排序给他一分为二,后面给出了算法使用了递归。

然后给出一个合并排序的示意图。 

作者给出的代码比较简洁,图形也比较简洁。

总结:整本书并未超越其他算法书的范畴,只是作者用一种比较好的便于理解的方式把现有算法分类,整体讲述内容并未超越其他书的模式。

 

大总结:相信经过对这些书的比较大家已经知道那些书是自己喜欢和需要的。算法书很多,好书也不说一个帖子可以展示完的,这一个帖子写了一个完整五一,还是没有写完,暂且先这样,我也不知道这样一种表述方式是否会得到大家的喜欢,如果很受欢迎就继续写续篇,把其他一些有特色的算法书一一展示给大家。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐