本书作者力图突破此类教材多年来形成的定式,在很多方面都做了大胆尝试。
在体例方面,作者结合多年教学实践,对知识点进行了重新整理编排,许多处理方法在同类教材中独树一帜,旨在将读者引向更高层次,使读者形成对数据结构的宏观认识。
在内容方面,本书并未对各种数据结构面面俱到,而是按照CC2001标准对必要知识点和技能要求精心加以裁剪,通过系统分类和启发式讲解,在基本数据结构与高级数据结构之间架起一座桥梁。
在算法方面,本书不仅强调对复杂度等基本概念的把握,同时结合具体问题介绍算法复杂度的各种分析方法,尤其是分摊分析等高级技巧。而且所有数据结构仍然构成一个完整的体系,帮助读者养成面向实际应用的意识,并掌握构建实际应用的基本能力。
要获取本书中的代码及相关教学资料,请访问:http://vis.cs.tsinghua.edu.cn/~deng/dsaj.htm。
无
关于计算机教育规范,最有权威、影响最大的莫过于ACM与IEEECS联合制订的Computing Curricula。比如,Computing Curricula 1991(CC1991)就曾对我国高校的计算机教育产生深刻的影响。正在制订中的CC2001(后改称CC2004)认为,随着近年来计算概念的快速发展,计算学科已经发展成为一个内涵繁杂的综合性学科,至少可以划分为计算机工程(CE)、计算机科学(CS)、信息系统(IS)、信息技术(IT)和软件工程(SE)五个领域,而且不同领域的人才所应具备的知识结构与能力侧重也不尽相同。尽管如此,从目前已经完成的部分来看,数据结构与算法在各领域的知识体系中仍占据重要的位置。比如在CE分卷(草案)中,Programming Fundamentals共39个核心学时,其中Algorithms and Problem Solving占8个学时,Data Structures占13个学时; 在CS分卷(正式稿)中,Programming Fundamentals共38个核心学时,其中Algorithms and Problem Solving占6个学时,Data Structures占14个学时。
为什么数据结构与算法长期以来一直受到如此重视呢?数据结构和算法是一对孪生兄弟,数据结构研究的问题包括数据在计算机中存储、组织、传递和转换的过程及方法,这些也是构成与支撑算法的基础。我们在编写计算机程序解决应用问题时,最终都要归结并落实到这两个问题上。正因为此,NWirth早在20世纪70年代就曾指出“程序=数据结构+算法”。近年来,随着面向对象技术的广泛应用,从数据结构的定义、分类、组成,到设计、实现与分析的模式和方法都有了长足的发展,现代数据结构更加注重和强调数据结构的整体性、通用性、复用性、简洁性和安全性。
为遵循上述原则,本书选择Java作为描述语言,因为相对于其他语言,Java语言比较完整、彻底地体现了面向对象的设计思想,这也是目前国际上同行们的一个主要取向。不过,关于Java语言本身的介绍,本书并未花费多少笔墨,而是直接假定读者已经熟练掌握了该语言。这既能缩减本书篇幅,也符合此领域教学今后的规范。比如,CC2001的CS分卷将Data Structures and Algorithms课程编号为CS103,并明确指出该课程是Programming Fundamentals(CS101)和The ObjectOriented Paradigm(CS102)的后续课程。
在内容选取、剪裁与体例结构上,作者力图突破现成的模式。这里并未对各种数据结构面面俱到,而是通过分类和讲解典型结构,力图使读者形成对数据结构的宏观认识; 并结合各部分的具体内容,在书中穿插了大量的问题,把更多的思考空间留给读者。
根据内容侧重,本书具体分为10章。
第1章是全书的基础,重点在于介绍算法与数据结构的关系,以及算法时间、空间复杂度的概念及其度量方法。
第2~4章覆盖了基本的数据结构,既有传统的栈与队列,也有更为抽象和通用的向量和列表。面向对象技术在现代数据结构理论中的重要地位在此得到体现,我们利用接口实现数据结构的封装,抽象出位置的概念,在向量和列表的基础上定义并实现序列结构,引入迭代器概念并针对上述结构具体实现。通过结合数组与链表结构的优点,第4章自然地导出了树结构的概念、实现及算法。
第5~7章介绍了若干高级数据结构。通过在一般性队列中引入优先级概念,导出了优先队列结构; 面向实际问题中的查找需求,导出了映射和词典结构; 针对全序集的查找问题,引入了查找树结构,并结合AVL树、伸展树和B树的实例介绍了平衡查找树结构的原理及其实现。面向对象的思想在这里继续得到贯彻,普遍采用了抽象、封装及继承等技术。
这一部分的侧重点逐渐转向算法,并结合具体问题介绍其应用与实现,包括堆结构的生成及调整算法、Huffman(赫夫曼)编码树算法、散列算法以及二路或多路平衡查找树的生成、插入、删除算法。在这三章中,读者也将对算法复杂度的各种分析方法有所了解。
第8~10章的论述重点完全转向算法。第8章对此前各章中陆续介绍过的排序算法进行了归纳与分类,着重介绍了归并排序算法与快速排序算法,并给出了此类算法的复杂度下界。结合串结构的应用,第9章着重讨论了串匹配问题,从蛮力算法出发,采用不同的启发式加速策略,分别介绍了KMP算法及BM算法。
关于图结构,第10章将重点放在相关算法上,并力图使初学者从各种图算法中梳理出清晰的脉络。为此,这里尝试通过一条主线——遍历——将各种算法串接起来。在这里,面向对象技术的魅力再次得以展现: 基于统一的图遍历算法模板,分别实现了深度优先、广度优先和最佳优先三大类遍历算法。实际上,这三类算法本身仍然以模板形式实现,包括边分类、可达分量、连通分量、最短路径以及最小生成树在内的各种具体算法,都进而基于这三个模板分别得到了实现。
书中涉及的所有代码,都符合J2SDK141规范,并构成一个名为dsa(Data Structures & Algorithms)的包; 所有类之间的扩展、继承关系,可以参见书后的“DSA类关系图”。
要获取本书中的代码及相关教学资料,请访问: http: //viscstsinghuaeducn/~deng/dsajhtm。
本书从筹划、撰写、审订到定稿,其间跨越三个年头,在此漫长的过程中,我的父母和妻子给了我巨大的支持,就这个意义而言,他们也是本书的完成者。年幼的女儿总是以她独有的方式,不时将我从写作和调试的苦海中解救出来,她让我体会了禁用PowerOff按钮的妙用(尽管除了拔掉接头外我还没有找到更好的办法,使得在她恶作剧地按下Reset按钮后依然能够继续写作)。我的确需要感谢她,她让我养成了及时备份的良好习惯,更使我意识到在离开电脑后自己依然能够而且更好地思考。
在清华大学执教多年,我日益深刻地体会到教育的伟大和神圣,是我的同事、学生使我懂得了如何忘却劳动的艰辛,并从教育的过程中获得乐趣。
我还要特别感谢机械工业出版社的温莉芳女士,在我一次次地推迟交稿时,她表现出的耐心与理解都令我既钦佩又惭愧,正是这非凡的宽容激励着我不断追求完美。
虽反复斟酌,在本书即将出版之际,内心依然惶恐。“丑媳妇终要见公婆”,恳请读者批评指正。
邓俊辉
2005年岁末定稿
无
无
第1章算法及其复杂度
11计算机与算法
111过指定垂足的直角边
112三等分线段
113排序
114算法的定义
12算法性能的分析与评价
121三个层次
122时间复杂度及其度量
123空间复杂度
13算法复杂度及其分析
131O(1)——取非极端元素
132O(logn)——进制转换
133O(n)——数组求和
134O(n2)——起泡排序
135O(2r)——幂函数
14计算模型
141可解性
142有效可解
143下界
15递归
151线性递归
152递归算法的复杂度分析
153二分递归
154多分支递归
第2章栈与队列
21栈
211栈ADT
212基于数组的简单实现
213Java虚拟机中的栈
214栈应用实例
22队列
221队列ADT
222基于数组的实现
223队列应用实例
23链表
231单链表
232基于单链表实现栈
233基于单链表实现队列
24位置
241位置ADT
242位置接口
25双端队列
251双端队列ADT
252双端队列接口
253双向链表
254基于双向链表实现的双端队列
第3章向量、列表与序列
31向量与数组
311向量ADT
312基于数组的简单实现
313基于可扩充数组的实现
314javautilArrayList类和javautilVector类
32列表
321基于节点的操作
322由秩到位置
323列表ADT
324基于双向链表实现的列表
33序列
331序列ADT
332基于双向链表实现序列
333基于数组实现序列
34迭代器
341迭代器ADT
342迭代器接口
343迭代器的实现
344Java中的列表及迭代器
第4章树
41术语及性质
411节点的深度、树的深度与高度
412节点的度与内部节点、外部节点
413路径
414祖先、后代、子树和节点的高度
415共同祖先及最低共同祖先
416有序树、m叉树
417二叉树
418满二叉树与完全二叉树
42树ADT及其实现
421“父亲长子弟弟”模型
422树ADT
423树的Java接口
424基于链表实现树
43树的基本算法
431getSize()——统计(子)树的规模
432getHeight()——计算节点的高度
433getDepth()——计算节点的深度
434前序、后序遍历
435层次遍历
436树迭代器
44二叉树ADT及其实现
441二叉树ADT
442二叉树的Java接口
443二叉树类的实现
45二叉树的基本算法
451getSize()、getHeight()和getDepth()
452updateSize()
453updateHeight()
454updateDepth()
455secede()
456attachL()和attachR()
457二叉树的遍历
458直接前驱、直接后继的定位算法
46完全二叉树的Java实现
461完全二叉树的Java接口
462基于向量的实现
第5章优先队列
51优先级、关键码、全序关系与优先队列
52条目与比较器
521条目
522比较器
523Comparator接口及其实现
53优先队列ADT及其Java接口
531优先队列的ADT描述
532优先队列的Java接口
533基于优先队列的排序器
54用向量实现优先队列
55用列表实现优先队列
551基于无序列表的实现及分析
552基于有序列表的实现及分析
56选择排序与插入排序
561选择排序
562插入排序
563效率比较
57堆的定义及性质
571堆结构
572完全性
58用堆实现优先队列
581基于堆的优先队列及其实现
582插入与上滤
583删除与下滤
584改变任意节点的关键码
585建堆
59堆排序
591直接堆排序
592就地堆排序
510Huffman编码树
5101二叉编码树
5102最优编码树
5103Huffman编码与Huffman编码树
5104Huffman编码树的构造算法
5105基于优先队列的Huffman编码树构造算法
第6章映射与词典
61映射
611映射的ADT描述
612映射的Java接口
613判等器
614javautil包中的映射类
615基于列表实现映射类
62散列表
621桶及桶数组
622散列函数
623散列码
624压缩函数
625冲突的普遍性
626解决冲突
627基于散列表实现映射类
628装填因子与重散列
63无序词典
631无序词典的ADT描述
632无序词典的Java接口
633列表式无序词典及其实现
634散列表式无序词典及其实现
64有序词典
641全序关系与有序查找表
642二分查找
643有序词典的ADT描述
644有序词典的Java接口
645基于有序查找表实现有序词典
第7章查找树
71二分查找树
711定义
712查找算法
713完全查找算法
714插入算法
715删除算法
716二分查找树节点类的实现
717二分查找树类的实现
718二分查找树的平均性能
72AVL树
721平衡二分查找树
722等价二分查找树
723等价变换
724AVL树
725插入节点后的重平衡
726节点删除后的重平衡
727AVL树的Java实现
73伸展树
731数据局部性
732逐层伸展
733双层伸展
734分摊复杂度
735伸展树的Java实现
736插入
737删除
74B树
741分级存储
742B树的定义
743关键码的查找
744性能分析
745上溢节点的处理
746关键码的插入
747下溢节点的处理
748关键码的删除
第8章排序
81归并排序
811分治策略
812时间复杂度
813归并算法
814Mergesort的Java实现
82快速排序
821分治策略
822轴点
823划分算法
824Quicksort的Java实现
825时间复杂度
83复杂度下界
831比较树与基于比较的算法
832下界
第9章串
91串及其ADT描述
92串模式匹配
921概念与记号
922问题
923算法效率的测试与评价
93蛮力算法
931算法描述
932算法实现
933算法分析
94KMP算法
941蛮力算法的改进
942next[]表的定义及含义
943KMP算法描述
944next[]表的特殊情况
945next[]表的构造
946next[]表的改进
947KMP算法的Java实现
948性能分析
95BM算法
951坏字符策略
952好后缀策略
953BM算法
954BM算法的Java实现
955性能
第10章图
101概述
1011无向图、混合图及有向图
1012度
1013简单图
1014图的复杂度
1015子图、生成子图与限制子图
1016通路、环路及可达分量
1017连通性、等价类与连通分量
1018森林、树以及无向图的生成树
1019有向图的生成树
10110带权网络
102抽象数据类型
1021图
1022顶点
1023边
103邻接矩阵
1031表示方法
1032时间性能
1033空间性能
104邻接表
1041顶点表和边表
1042顶点与邻接边表
1043边
1044基于邻接表实现图结构
105图遍历及其算法模板
106深度优先遍历
1061深度优先遍历算法
1062边分类
1063可达分量与DFS树
1064深度优先遍历算法模板
1065可达分量算法
1066单强连通分量算法
1067强连通分量分解算法
1068浓缩图与弱连通性
107广度优先遍历
1071广度优先遍历算法
1072边分类
1073可达分量与BFS树
1074广度优先遍历算法模板
1075最短距离算法
108最佳优先遍历
1081最佳优先遍历算法
1082最佳优先遍历算法模板
1083最短路径
1084最短路径序列
1085Dijkstra算法
1086最小生成树
1087PrimJarnik算法DSA类关系图