数据结构是计算机存储和组织数据的方式,选择合适的数据结构可以极大地提高程序的效率和性能。下面我将一些最常用的数据结构进行分类介绍
1. 线性结构
1.1 数组
- 特点:在内存中占据一段连续的空间。通过索引(下标)可以快速访问任意位置的元素(时间复杂度 O(1))。但大小固定,插入和删除元素效率较低(平均需要移动元素,时间复杂度 O(n))。
- 场景:需要频繁随机访问元素、已知数据规模或规模变化不大的情况。
1.2 链表
-
特点:通过“指针”将一组零散的内存块串联起来。插入和删除效率高(只需要改变指针指向,时间复杂度 O(1))。但访问元素需要从头遍历(时间复杂度 O(n)),且需要额外的空间存储指针。
-
常见变种:
- 单向链表:每个节点只指向下一个节点。
- 双向链表:每个节点指向前一个和后一个节点,支持双向遍历。
- 循环链表:尾节点指向头节点,形成一个环。
-
场景:频繁进行插入和删除操作、不确定数据规模的情况(如实现队列、LRU缓存)。
1.3 栈
- 特点:一种后进先出的操作受限的线性表。只允许在一端(栈顶)进行插入(入栈/Push)和删除(出栈/Pop)操作。
- 场景:函数调用栈、表达式求值、括号匹配、浏览器前进/后退功能。
1.4 队列
-
特点:一种先进先出的操作受限的线性表。只允许在一端(队尾)进行插入(入队/Enqueue),在另一端(队头)进行删除(出队/Dequeue)。
-
常见变种:
- 双端队列:两端都允许进行插入和删除操作。
- 优先队列:出队顺序由元素的“优先级”决定,通常用堆来实现。
-
场景:任务调度、消息队列、广度优先搜索(BFS)。
2. 树形结构
2.1 二叉树
-
特点:每个节点最多有两个子节点(左子节点和右子节点)。
-
常见类型:
- 二叉搜索树:左子树所有节点的值 < 根节点的值 < 右子树所有节点的值。其中平衡二叉搜索树(如AVL树、红黑树)保证了查询、插入、删除的时间复杂度都是 O(log n),效率极高。
- 堆:一种完全二叉树。最大堆的父节点值总大于等于子节点;最小堆的父节点值总小于等于子节点。
-
场景:
- BST:用于实现高效的动态数据查找(如数据库索引)。
- 堆:实现优先队列、堆排序、Top K问题。
2.2 字典树
- 特点:专门用于处理字符串。利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较。
- 场景:搜索引擎的自动补全、拼写检查、IP路由表。
2.3 B+ 树
- 特点:一种多路平衡搜索树,一个节点可以有多个子节点。大大降低了树的高度,减少了磁盘I/O次数。
- 场景:数据库和文件系统的索引。几乎所有主流数据库(如MySQL)的索引都使用B+树。
3. 散列表(哈希表)
- 特点:通过哈希函数将键映射到数组中的一个位置来进行访问。理想情况下,查找、插入、删除操作的时间复杂度都可以接近 O(1) 。
- 挑战:需要处理哈希冲突(不同的键映射到同一位置),常用解决方法有链地址法(用链表存储冲突元素)和开放地址法。
- 场景:需要极快查找速度的场景,如实现字典、缓存(Redis)、集合。
4. 图
-
特点:由顶点和边组成,用于表示多对多的复杂关系。
-
存储方式:
- 邻接矩阵:用一个二维数组表示顶点之间的连接关系。查询快,但稀疏图非常浪费空间。
- 邻接表:为每个顶点维护一个链表,存储与其相连的顶点。节省空间,是更常用的方式。
-
场景:社交网络(顶点是用户,边是好友关系)、地图导航(顶点是地点,边是道路)、推荐系统。
5. 总结
以上就是常用的数据结构,可能在实际的开发中,我们百分之九十只会用到线性结构,接下来我们对上面的数据结构进行一个总结和对比
| 数据结构 | 特点 | 优点 | 缺点 | 典型应用 |
|---|---|---|---|---|
| 数组 | 连续内存,索引访问 | 随机访问快 | 大小固定,插入删除慢 | 任何需要随机访问的场景 |
| 链表 | 离散内存,通过指针连接 | 插入删除快 | 随机访问慢 | 队列,LRU缓存,链表反转 |
| 栈 | 后进先出 | 实现简单 | 功能受限 | 函数调用,括号匹配 |
| 队列 | 先进先出 | 实现简单 | 功能受限 | 任务调度,BFS |
| 哈希表 | 键值对,哈希函数 | 查找插入删除快 | 无序,可能有哈希冲突 | 字典,缓存,集合 |
| 二叉搜索树 | 有序,左-根-右 | 查找插入删除快 | 可能会退化为链表 | 动态数据查找 |
| 堆 | 父节点总 大于/小于 子节点 | 快速获取最大最小值 | 其他操作相对慢 | 优先队列 |
| 图 | 顶点和边 | 建模复杂关系 | 算法复杂 | 社交网络,路径规划 |
选择数据结构的核心思路是:分析你的核心操作(是查找多,还是插入删除多?是否需要有序?),然后选择能让你核心操作效率最高的那一个。
那么后面我将从代码层面出发,一个一个去实现上述的数据结构