第一部分:引论
这部分主要建立基本概念,是后续所有内容的基础。

什么是算法?
- 定义:算法是解决特定问题的一系列清晰、有限的指令步骤。
- 核心要素:输入、输出、确定性(无歧义)、可行性、有穷性。
- 例子:菜谱就是算法,告诉你如何用有限的步骤(输入食材)做出一道菜(输出菜品)。
什么是数据结构?
- 定义:数据结构是计算机中存储、组织数据的方式,它不仅包含数据元素本身,还包含数据元素之间的关系。
- 核心思想:选择合适的数据结构,可以让算法更高效。
- 例子:电话簿按姓氏排序(一种数据组织方式),让你能快速找到某个人的号码。
算法分析:大O表示法
这是衡量算法效率的核心工具,它描述的是算法执行时间(或空间)与输入规模 n 之间的增长趋势,而不是具体的运行时间。
- 目的:忽略硬件、编程语言等具体因素,专注于算法本身的效率。
- 常见复杂度(从优到劣):
- O(1) - 常数时间:操作时间与输入规模无关,数组通过索引访问元素。
- O(log n) - 对数时间:每次操作都将问题规模减半,二分查找。
- O(n) - 线性时间:操作时间与输入规模成正比,遍历一个数组。
- O(n log n) - 线性对数时间:非常高效的排序算法复杂度,归并排序、快速排序。
- O(n²) - 平方时间:嵌套循环导致时间与规模的平方成正比,简单的冒泡排序、选择排序。
- O(2ⁿ) - 指数时间:通常用于暴力解决组合问题,效率极低,不可扩展。
Java基础回顾
书中会简要回顾Java的一些关键特性,因为它们是实现数据结构的基础:
- 基本数据类型:
int,double,char等。 - 数组:固定大小的连续内存空间,支持快速随机访问。
- 泛型:允许在编写代码时使用一个类型占位符,增强代码的类型安全性和复用性。
ArrayList<Integer>。 - 接口:定义一组方法的契约,是实现多态和抽象的关键。
- 异常处理:用于处理程序运行时的错误。
第二部分:基本数据结构
这部分介绍最基础、最常用的数据结构。
线性表
- 数组:
- 特点:大小固定,内存连续,支持O(1)时间访问,但插入和删除(尤其是中间位置)需要移动大量元素,是O(n)操作。
- Java实现:原生数组
int[],以及ArrayList(动态数组,内部使用数组实现,能自动扩容)。
- 链表:
- 特点:由一系列节点组成,每个节点包含数据和指向下一个节点的指针,内存不连续,插入和删除操作快(O(1),若已知节点位置),但访问元素需要从头遍历(O(n))。
- Java实现:
LinkedList(Java集合框架中的双向链表实现)。 - 常见类型:单链表、双链表、循环链表。
栈
- 特点:后进先出 的数据结构,就像一摞盘子,最后放上去的第一个被拿走。
- 核心操作:
push(入栈),pop(出栈),peek(查看栈顶元素)。 - Java实现:
Stack类(较老,推荐使用LinkedList或ArrayDeque来模拟栈,因为它们性能更好)。 - 应用场景:函数调用栈、表达式求值、括号匹配、浏览器历史记录等。
队列
- 特点:先进先出 的数据结构,就像排队买票,先来的人先服务。
- 核心操作:
enqueue(入队),dequeue(出队)。 - Java实现:
Queue接口,常用实现有LinkedList和ArrayDeque。 - 应用场景:任务调度、消息缓冲、广度优先搜索算法。
第三部分:树
树是用于表示层级关系的重要数据结构。

树的基本概念
- 节点、边、根、父节点、子节点、兄弟节点、叶子节点、高度、深度。
二叉树
每个节点最多有两个子节点(左子节点和右子节点)。
- 二叉搜索树:
- 特点:左子树所有节点的值都小于根节点,右子树所有节点的值都大于根节点,这使得查找、插入、删除的平均时间复杂度为 O(log n)。
- 问题:在最坏情况下(如插入已排序的数据),BST会退化成一个链表,复杂度变为O(n)。
- 平衡二叉树:为了解决BST的退化问题而生。
- AVL树:任何节点的两个子树的高度差最多为1,在插入和删除时会通过旋转操作来维持平衡。
- 红黑树:通过在节点上增加“颜色”属性和一系列规则来保证树的近似平衡,Java集合框架中的
TreeMap和TreeSet就是基于红黑树实现的。
堆
- 特点:一种特殊的完全二叉树,分为最大堆(父节点值 >= 子节点值)和最小堆(父节点值 <= 子节点值)。
- 核心操作:
insert(插入),deleteMax/deleteMin(删除根节点)。 - 应用场景:优先级队列(
PriorityQueue的底层实现)、堆排序。 - Java实现:
PriorityQueue类(默认是最小堆)。
其他树
- B树/B+树:用于数据库和文件系统,能够高效处理大规模数据的磁盘I/O。
- 字典树:用于高效地存储和检索字符串集合,如实现自动补全功能。
第四部分:散列
散列是一种通过散列函数将键映射到数组索引位置,以实现快速查找的技术。
核心概念
- 散列表:实现散列的数据结构,通常是一个数组。
- 散列函数:将任意大小的键映射到数组索引的函数,好的散列函数应能均匀分布数据,减少冲突。
- 冲突:两个不同的键通过散列函数计算出相同的索引,这是散列技术必须处理的核心问题。
冲突解决方法
- 分离链接法:将冲突的元素以链表的形式存储在同一个散列桶中。
- 开放寻址法:当发生冲突时,按照一定的规则在散列表中寻找下一个“空槽”来存储元素,常见的探测方法有线性探测、二次探测等。
Java实现
HashSet:基于散列表实现的Set集合,不存储重复元素,不保证元素顺序。HashMap:基于散列表实现的Map集合,存储键值对,通过键快速查找值,不保证键的顺序。Hashtable:一个较老的线程安全的实现,现在已被HashMap(配合Collections.synchronizedMap)和ConcurrentHashMap替代。
第五部分:优先队列
优先队列是一种特殊的队列,每次出队的是队列中“优先级最高”的元素。
- 实现方式:
- 未排序数组/链表:插入O(1),删除O(n)。
- 排序数组/链表:插入O(n),删除O(1)。
- 堆:插入和删除的平均时间复杂度均为 O(log n),是最高效的实现方式。
- Java实现:
PriorityQueue类,默认使用最小堆。
第六部分:排序
排序是算法学习的重中之重。

简单排序算法
- 冒泡排序:O(n²)
- 选择排序:O(n²)
- 插入排序:O(n²),但在小规模或部分有序的数组上表现很好。
高效排序算法
- 归并排序:
- 思想:分治法,将数组递归地分成两半,分别排序,然后合并两个有序数组。
- 复杂度:O(n log n),稳定排序,但需要O(n)的额外空间。
- 快速排序:
- 思想:分治法,选择一个“基准”元素,将数组分为两部分,一部分小于基准,一部分大于基准,然后递归地对这两部分进行排序。
- 复杂度:平均 O(n log n),最坏 O(n²)(可以通过随机化选择基准来避免),原地排序(空间复杂度O(log n)),不稳定排序,在实践中通常比归并排序更快。
- 堆排序:
- 思想:利用堆的特性,将数组构建成一个最大堆,然后反复取出堆顶元素并调整堆。
- 复杂度:O(n log n),原地排序,不稳定排序。
Java中的排序
Arrays.sort()和Collections.sort():对于基本类型(如int[]),使用双轴快速排序(一种优化的快速排序),对于对象(如List<Integer>),使用归并排序或TimSort(一种混合了归并排序和插入排序的算法,对小数组使用插入排序)。
第七部分:不相交集合
也称为并查集,是一种用于处理动态连通性问题的数据结构。
- 核心操作:
find(u): 查找元素u所在的集合(通常返回代表元素)。union(u, v): 合并元素u和v所在的两个集合。
- 优化技术:
- 路径压缩:在
find操作中,将查找路径上的节点直接指向根节点,降低树的高度。 - 按秩合并:在
union操作中,将较小的树连接到较大的树下面,保持树的平衡。
- 路径压缩:在
- 应用场景:Kruskal算法求最小生成树、图像处理、网络连通性分析等。
第八部分:图
图是由顶点和边组成的非线性数据结构,用于表示多对多的关系。
图的表示
- 邻接矩阵:一个二维数组,
matrix[i][j]表示顶点i和j之间是否有边,适合稠密图。 - 邻接表:一个数组,数组的每个元素是一个链表(或动态数组),存储与该顶点相邻的所有顶点,适合稀疏图。
图的遍历
- 广度优先搜索:使用队列,逐层遍历图,可以用来寻找无权图的最短路径。
- 深度优先搜索:使用栈(或递归),沿着一条路径走到尽头再回溯,可以用来检测环、拓扑排序等。
图的应用算法
- 最短路径:
- Dijkstra算法:单源最短路径,适用于非负权图。
- Bellman-Ford算法:单源最短路径,可以处理负权边。
- 最小生成树:
- Prim算法:从一个顶点开始,逐步扩展生成树。
- Kruskal算法:按边的权重从小到大选择,利用不相交集合来避免环。
- 拓扑排序:对有向无环图中的顶点进行排序,使得对于每一条有向边
(u, v),顶点u都在v的前面。
《数据结构与算法分析:Java语言描述》这本书系统地介绍了计算机科学的核心知识,学习它的路径应该是:
- 理解基础:掌握大O分析、数组和链表。
- 掌握线性结构:深入理解栈、队列。
- 攻克树与图:这是难点也是重点,特别是BST、堆、图的遍历和经典算法。
- 学习高级技巧:散列、优先队列、不相交集合。
- 实践应用:亲手用Java实现这些数据结构和算法,并分析它们的性能。
这本书不仅是知识的罗列,更重要的是培养一种计算思维,即如何根据问题的特点,选择最合适的数据结构和算法来优雅高效地解决问题。
