- 核心思想:学习这门课的目的是什么?
- 核心数据结构:线性、树形、图形结构。
- 核心算法:排序、查找、图算法。
- 算法分析:如何衡量算法的好坏?
- C语言实现要点:与C++/Java等语言相比,在C中实现时需要注意什么?
- 学习资源与建议:书籍、网站和练习方法。
核心思想:为什么学习数据结构与算法?
数据结构是“如何组织数据”,算法是“如何处理数据”,两者相辅相成,共同决定了程序的效率和质量。

(图片来源网络,侵删)
- 效率:一个糟糕的算法在处理大量数据时会变得极其缓慢,甚至无法完成任务,在一个百万级别的用户列表中查找一个用户,用暴力查找可能需要几秒,而用哈希表可能只需要几微秒。
- 质量:好的数据结构能让代码更清晰、更易于维护和扩展,用树结构来表示文件系统,比用一个大数组来模拟要直观得多。
学习目标:
- 掌握常用数据结构的原理、实现和应用场景。
- 掌握核心算法的思想、实现和复杂度分析。
- 能够根据具体问题,选择最合适的数据结构和算法。
- 具备编写高效、健壮代码的能力。
核心数据结构
数据结构通常分为两大类:线性结构和非线性结构。
A. 线性结构
元素之间存在一对一的线性关系。
| 数据结构 | 描述 | C语言实现核心 | 优点 | 缺点 |
|---|---|---|---|---|
| 数组 | 一块连续的内存空间,通过索引访问。 | int arr[10]; |
随机访问快(O(1)),空间紧凑。 | 大小固定,插入/删除元素慢(O(n))。 |
| 链表 | 由节点组成,每个节点包含数据和指向下一个节点的指针。 | struct Node { int data; struct Node* next; }; |
大小动态,插入/删除快(O(1),若已知位置)。 | 随机访问慢(O(n)),需要额外指针空间。 |
| 栈 | 后进先出 的线性结构。 | 通常用数组或链表实现,并限制访问为一端(栈顶)。 | 操作简单(push, pop),能实现函数调用、表达式求值等。 |
无法随机访问中间元素。 |
| 队列 | 先进先出 的线性结构。 | 通常用链表或循环数组实现。 | 符合现实逻辑(如排队任务处理),能实现广度优先搜索。 | 无法随机访问中间元素。 |
| 哈希表 | 通过哈希函数将键映射到数组索引,实现快速查找。 | 数组 + 链表(或开放寻址法)处理冲突。 | 查找、插入、删除的平均时间复杂度接近 O(1)。 | 最坏情况下性能可能退化(O(n)),哈希函数设计复杂,空间占用较大。 |
B. 非线性结构
元素之间存在一对多或多对多的关系。

(图片来源网络,侵删)
| 数据结构 | 描述 | C语言实现核心 | 优点 | 缺点 |
|---|---|---|---|---|
| 树 | 分层的数据结构,由节点和边组成,有且仅有一个根节点。 | struct TreeNode { int data; struct TreeNode* left; struct TreeNode* right; }; (二叉树) |
层次关系清晰,搜索效率高(二叉搜索树),常用于表示文件系统、表达式等。 | 树的平衡问题(如二叉搜索树可能退化为链表)。 |
| 二叉搜索树 | 一种特殊的二叉树,左子树所有节点 < 根节点 < 右子树所有节点。 | 在 TreeNode 结构上实现插入、删除、查找逻辑。 |
查找、插入、删除的平均时间复杂度为 O(log n)。 | 若数据有序,会退化为链表,操作变为 O(n)。 |
| 堆 | 一种特殊的完全二叉树,分为大顶堆(父节点 >= 子节点)和小顶堆。 | 通常用数组实现,利用下标关系计算父子节点位置 (i*2+1, i*2+2)。 |
能快速找到最大/最小值(O(1)),构建堆和堆调整效率高(O(log n))。 | 查找特定元素效率不高(O(n))。 |
| 图 | 由顶点 和边 组成的非线性结构,用于表示多对多的关系。 | 邻接矩阵:二维数组 int matrix[V][V]。邻接表:数组 + 链表, struct Graph { int V; struct Node** adj; }; |
能表示复杂的网络关系(如社交网络、地图导航)。 | 实现相对复杂,空间和时间消耗较大。 |
核心算法
算法是解决问题的步骤,以下是几类最重要的算法。
A. 排序算法
将一组无序数据按特定顺序(升序/降序)排列。
| 算法 | 平均时间复杂度 | 最坏时间复杂度 | 空间复杂度 | 稳定性 | 描述 |
|---|---|---|---|---|---|
| 冒泡排序 | O(n²) | O(n²) | O(1) | 稳定 | 简单但低效,反复交换相邻元素。 |
| 选择排序 | O(n²) | O(n²) | O(1) | 不稳定 | 每次从未排序部分找到最小元素放到已排序末尾。 |
| 插入排序 | O(n²) | O(n²) | O(1) | 稳定 | 将元素逐个插入到已排序部分的正确位置。 |
| 希尔排序 | O(n log n) ~ O(n²) | O(n²) | O(1) | 不稳定 | 插入排序的改进,通过分组进行预排序。 |
| 归并排序 | O(n log n) | O(n log n) | O(n) | 稳定 | 分治策略,将数组分成两半,分别排序后合并。 |
| 快速排序 | O(n log n) | O(n²) | O(log n) (栈空间) | 不稳定 | 分治策略,选择一个基准,将数组分为两部分。实际应用中最常用。 |
| 堆排序 | O(n log n) | O(n log n) | O(1) | 不稳定 | 利用堆数据结构,每次取堆顶元素,然后调整堆。 |
注:稳定性指相等元素的相对顺序在排序后是否保持不变。
B. 查找算法
在数据集合中寻找特定元素。

(图片来源网络,侵删)
| 算法 | 时间复杂度 | 描述 |
|---|---|---|
| 顺序查找 | O(n) | 从头到尾遍历数组,直到找到目标,适用于无序数据。 |
| 二分查找 | O(log n) | 要求数据有序,每次查找都将范围缩小一半。 |
| 哈希查找 | 平均 O(1),最坏 O(n) | 通过哈希函数直接计算出元素可能的位置。 |
C. 图算法
用于解决图中的相关问题。
| 算法 | 应用场景 | 描述 |
|---|---|---|
| 深度优先搜索 | 路径查找、拓扑排序、连通性判断 | 尽可能深地探索图的分支,像“走迷宫”一样,常用递归或栈实现。 |
| 广度优先搜索 | 最短路径(无权图)、连通性判断 | 逐层探索图,像“水波纹”一样扩散,常用队列实现。 |
| 迪杰斯特拉算法 | 单源最短路径 | 计算从一个顶点到所有其他顶点的最短路径。 |
| 弗洛伊德算法 | 多源最短路径 | 计算任意两个顶点之间的最短路径。 |
算法分析:大O表示法
这是衡量算法效率的核心工具,它描述的是算法运行时间与输入规模n之间的增长关系,关注的是最坏情况或平均情况下的渐进行为。
- O(1) - 常数时间:运行时间与输入大小无关,数组访问
arr[0]。 - O(log n) - 对数时间:运行时间随n的增长而缓慢增长,二分查找。
- O(n) - 线性时间:运行时间与n成正比,遍历数组。
- O(n log n) - 线性对数时间:非常高效的排序算法复杂度,归并排序、快速排序。
- O(n²) - 平方时间:运行时间随n的平方增长,冒泡排序、嵌套循环。
- O(2ⁿ) - 指数时间:运行时间随n呈指数级增长,通常用于暴力破解问题,效率极低。
分析步骤:
- 找出算法的基本操作(如循环中的比较、赋值)。
- 计算基本操作执行的次数T(n)。
- 用大O表示法简化T(n),忽略常数项和低阶项。
示例:
// 计算 sum = 1 + 2 + ... + n
int sum(int n) {
int sum = 0;
for (int i = 1; i <= n; i++) { // 循环 n 次
sum += i; // 基本操作
}
return sum;
}
// T(n) = n
// 时间复杂度为 O(n)
C语言实现要点
与C++/Java等自带高级数据结构的语言相比,用C语言实现需要更多底层操作。
-
内存管理:
malloc,calloc,realloc,free是你的好朋友,你需要手动为链表、树、图等动态分配内存。- 务必检查内存分配是否成功,否则会导致程序崩溃。
- 防止内存泄漏:
free掉所有动态分配的内存。
-
指针是核心:
- 链表、树、图等结构完全依赖于指针来连接各个节点,必须熟练掌握指针的运算(
->, ,&)。 - 函数参数传递指针,才能修改外部数据结构(如链表的删除操作)。
- 链表、树、图等结构完全依赖于指针来连接各个节点,必须熟练掌握指针的运算(
-
结构体:
- 用
struct来定义数据结构的节点,如struct Node,struct TreeNode。
- 用
-
缺乏泛型:
- C语言没有模板,如果你想创建一个能存储任何类型数据的链表,通常有两种方法:
- *`void
指针**:在节点中存储void data,在存入时强制转换(void)`,取出时再转换回来,这会丢失类型安全。 - 宏:使用宏来生成类型无关的代码,但可读性和调试性较差。
- *`void
- C语言没有模板,如果你想创建一个能存储任何类型数据的链表,通常有两种方法:
-
错误处理:
- 很多操作都可能失败(如
malloc失败、文件打开失败),需要用返回值(如NULL)或错误码来通知调用者。
- 很多操作都可能失败(如
学习资源与建议
推荐书籍
-
《数据结构与算法分析:C语言描述》 - Mark Allen Weiss
- 经典中的经典,讲解清晰,数学推导严谨,代码示例完整且质量高,是绝大多数高校的指定教材。
-
《C程序设计语言》 - Brian W. Kernighan & Dennis M. Ritchie (K&R)
C语言的“圣经”,在学习数据结构之前,必须对C语言本身(特别是指针和内存管理)有扎实的掌握。
-
《数据结构》 - 严蔚敏
国内经典教材,非常全面,但代码示例是类C语言或伪代码,需要自己动手翻译成C。
在线资源
-
VisuAlgo (https://visualgo.net)
- 强烈推荐!通过动画可视化各种数据结构和算法,帮助你直观理解工作原理。
-
GeeksforGeeks (https://www.geeksforgeeks.org)
内容极其丰富的算法与数据结构教程,包含大量C/C++/Java的实现和面试题。
-
LeetCode (https://leetcode.cn)
刷题平台是检验学习成果和提升编码能力的最佳方式,从“简单”题开始,逐步挑战“中等”和“困难”题。
学习建议
- 先理解,再编码:不要一上来就抄代码,先用纸和笔模拟算法的执行过程,理解其思想。
- 多动手,多实现:亲手把书上的数据结构和算法用C语言实现一遍,只有写出来,才知道哪里没懂。
- 画图,画图,再画图:链表、树、图的指针关系非常复杂,画图是最好的理解方式。
- 分析复杂度:每写完一个算法,都试着分析一下它的时间复杂度和空间复杂度。
- 刷题巩固:在LeetCode上找对应的数据结构和算法题目来做,将理论应用到实践中。
祝你学习顺利!数据结构与算法是编程的内功,一旦掌握,将让你受益终身。
