数据结构
介绍
基本概念
- 数据元素:数据的基本单位
- 数据项:具有独立含义的数据最小单位
- 数据对象:性质相同的数据元素的集合
- 数据结构:所有数据元素及其关系
逻辑结构和存储结构
逻辑结构
- 集合
- 线性:线性表、有序表、栈、队列、双端队列、串
- 树形:树、二叉树
- 图形:图
存储结构
- 顺序存储:顺序表、顺序栈等
- 链式存储:单向链表、双向链表、循环链表、链栈等
- 索引存储:索引
- 散列存储:哈希表
线性表
逻辑结构
- 有穷性:元素个数有限
- 一致性:所有元素性质相同
- 序列性:每个元素只有一个前驱节点和后继节点
顺序表
操作 | 时间复杂度 | 空间复杂度 |
---|---|---|
访问 | ||
增加 | ||
删除 |
插入算法
- 元素后移,最少 0 次,最大 N 次
- 赋值
平均移动次数:
删除算法
步骤:元素前移,最少 0 次,最大 N-1 次
平均移动次数:
分区算法
分区算法是快速排序的一部分。
设置基准值,通常是第一个值
备份基准值
设置双指针:
i
指向头,j
指向尾向左扫描,寻找一个比基准值小的元素,其索引为
j
- 扫描过程中可能会出界
移动这个元素到
i
所在位置上- 如果是第一次移动,那么
i
就是初始值,也就是基准值的位置,这个时候可以直接替换,因为基准值已经备份了。 - 如果这不是第一次移动,那么
i
就是上次使用的值,但它的值已经被放到了另外一个地方。
- 如果是第一次移动,那么
向右扫描,寻找一个比基准值小的元素,其索引为
i
- 扫描过程中可能会出界
移动这个元素到
j
所在位置上j
就是上次使用的值,但它的值已经被放到了另外一个地方
重复 4-7,直到
i
小于j
- 当循环终止时,
i
等于j
- 当循环终止时,
1 | //[low,high) |
下面的算法和上面的算法思路差不多,唯一的区别是把两次赋值改成了交换。
需要注意的是:
- 循环体内交换前需要 判断 i、j 是否相等
- 循环体外的交换不要使用
mid
,因为mid
和arr[low]
的地址不同 - 实际上,在整个过程中,
arr[low]
是不变的,因为第一次循环有arr[low] <= mid
,增长后i
最小也是low+1
。也就是说,这类解法 备份基准元素 是可选的,因为基准元素所在位置不会被赋其他值。
1 | //[low,high) |
单向链表
操作 | 时间复杂度 | 空间复杂度 |
---|---|---|
访问 | ||
增加 | ||
删除 |
插入元素
顺序:
- 非首节点:创建节点->链接后节点->链接前节点
- 首节点:创建节点->链接后节点->修改首指针
删除元素
顺序:
- 非首节点:保存节点->前后连接->删除节点
- 首节点:保存节点->修改首指针->删除节点
创建链表
- 头插法
- 头插法通常会事先准备一个额外的节点,可能是空节点或者链表信息节点
- 每次插入时,指向这个额外的节点的指针不动
graph LR NODEH(链表信息)-->NODEI1(A:i-1)-->NODEE(...)-->NODE1(A:1)
1 | current->next = head->next; |
- 尾插法
- 可以不准备额外的节点
- 每次插入时,指向这个额外的节点的指针移动到插入节点的末尾
graph LR NODEH(链表信息)-->NODE1(A:1)-->NODEE(...)-->NODEI1(A:i-1)
1 | // current 即将插入的节点;last 最后一个节点 |
循环条件
1 | //current 迭代结点 |
循环链表
循环链表在单链表的基础上,将首尾节点连接起来。
循环条件
1 | //head 头结点,current 迭代节点 |
栈
一种后进先出的数据结构 LIFO。
主要操作: 入栈、出栈。
应用:表达式解析、括号匹配、DFS
队列
一种先进先出的数据结构 FIFO。
主要操作: 入队、出队
应用:BFS
循环队列
设 head
为队首,tail
为队尾,size
为队列的长度,i
为数组下标。
- 队空条件:
head == tail
- 队满条件:
(tail+1)%size=head
- 迭代器:
(i+1)%size
(递增迭代) 和(i-1+size)%size
(递减迭代)
数组和广义表
矩阵的压缩存储
- 对称矩阵的压缩存储:存储一半就行。
,()
,(),(i,j)调换就行
- 三角矩阵的压缩存储:
下三角:
树
表示
- 树形
- 文氏图
- 凹入表示
- 括号表示
基本概念
- 节点的度:结点子树个数
- 树的度:所有结点度的最大值
- m 次树:度数为 m 的树
- 树的结点等于度数加一
存储结构
- 双亲存储结构:一个数组,存储某个数据的父下标
- 孩子链存储结构
- 孩子兄弟链存储结构
二叉树
介绍
满二叉树
- 所有分支结点都有左右孩子
- 叶子结点在二叉树的底下
- 只有度为 0 和度为 2 的节点
完全二叉树
- 只有最下面两层结点度数小于 2,度数为 1 的只能在最后一层最左边的位置
二叉树的性质
- 非空二叉树:叶子节点数=双分支结点数+1,
二叉树与普通树的转换
左孩子,右兄弟
存储结构
完全二叉树顺序存储
- 求父元素:$\left \lfloor \frac{i}{2} \right \rfloor $
- 求左子元素:
- 第 i 行第一个元素:
遍历
前序遍历:访问根节点->访问左子树->访问右子树
中序遍历:访问左子树->访问根节点->访问右子树
后序遍历:访问左子树->访问右子树->访问根节点
层次遍历:BFS
求序列问题:先写根节点(前序在开头,中序在中间,后序在末尾,然后留空位置),再写左节点,再写右节点
由序列构造树:
- 条件:中序序列+(前/后)序列任意一个
- 方法:
- 中序序列中间的某个位置对应着根
- 前后序列的起始(或终止)位置对应着根
线索二叉树:
- 方法:把空的左指针指向遍历序列的前驱结点,空的右指针指向遍历序列的后继
- 提高遍历的空间效率
- 遍历方法:指向首节点、寻找右子树
哈夫曼树
目的:求最小带权路径长度 WPL,其中, 为权重, 为路径长度,为叶子结点数
步骤
- 定义一个森林,包含所有叶子节点
- 选择最小的两个节点,组合在一起,形成的新树,放入森林
- 重复操作,直到森林只有一棵树
哈夫曼编码:左边路径标 0,右边路径标 1,按照路径组合成编码
图
存储结构
- 邻接矩阵
- 邻接表
遍历
深度优先遍历 DFS
- 过程:访问初始点 v->寻找未被访问的点 w->以 w 为初始点进行深度优先遍历
- 应用:寻找路径、寻找所有路径
1 | bool visited[MAX_SIZE]; |
广度优先搜索
- 过程:初始点 v 入队->若队列不为空,则循环从队列中取出一个元素 w->寻找 w 相邻的所有未访问的元素,并入队
- 应用:寻找最短路径
1 | template <typename T> |
最小生成树
- 概念:生成树中各边权值最小的树称为最小生成树
Prim 算法
- 用两个集合 U,V 分别表示找到的点集,和未找到的点集;
- 以 U 中的点为起点 a,在 V 中找一个点为终点 b,要求这两个点构成的边(a,b)的权值是其余不成环的边中最小的
- 重复第二步,直至 V 中的点集为空,U 中的点集为满
Kruskal 算法
每次找最小的且不成环的一条边
最短路径
Dijkstra 算法
过程:
- 定义一个 dist 数组表示起始点到下标为 i 的节点的最短路径,一个 path 数组表示当前下标为 i 的节点的上一个节点位置,集合 U 表示已加入的节点
- 计算起始点链接到的各个边的权值,并写入 dist 数组,如果没有边则设置 -1
- 从 dist 数组中寻找未走过且路径最短的点 p
- 将 p 加入 U,然后重新计算 距离(
距离[i] = dist[p]+p到i的距离
),如果距离下降则修改dist
,对发生改动的下标,在 path 相应下标下,修改值为 p - 重复操作,直到 U 满了
求解:
- 到 i 的最短路径长度:dist[i]
- 求具体路径:path[i] 的值为上一个节点的位置,一直寻找,直到值为 0
拓扑排序
步骤:
- 找一个没有前驱的节点并输出它
- 删掉这个节点
- 重复前两步,直到找不到没有前驱的节点
结果:如果输出了全部元素,则图中没有回路,否则有回路
查找
线性表的查找
- 顺序查找
- 成功查找长度:
- 折半查找:找中点->改区间 循环
- 求查找长度:画二叉排序树
树表的查找
二叉排序树的创建:
- 小的放左边,大的放右边
- 左子树元素都比根小,右子树都比根大
- 其中序序列递增有序
计算查找长度
- 成功:路径权值和取平均
- 失败:补上树中所有空缺的节点,计算空缺的节点路径权值和取平均
哈希表
概念: 把关键字 映射为 的地址
哈希冲突:
- 线性探测法:遇到冲突就右移,右边没有了再从数组开始位置开始找
- 平方探测法:只探测下标 d 中, 的位置
- 拉链法:把冲突的元素用链表进行连接
查找长度计算:探测次数之和
小结
排序
直接插入排序
每次将无序区的第一个元素插入到有序区的指定位置
折半插入排序
每次将无序区的第一个元素插入到有序区的指定位置,不同的是找插入位置的方式为二分查找
希尔排序
每次排序时指定一个 d,将表中的元素分成 d 组,每组进行直接插入排序,再取更小的 d 进行排序,直到 d 等于 1
冒泡排序
每轮排序比较相邻两个元素,前面大于后面则交换,直到不发生交换为止。
快速排序
找一个基准,将表分成小于基准值和大于基准值两部分,然后分别对这两部分进行快速排序。
1 | //[low,high) |
各种排序算法的比较
- 标题: 数据结构
- 作者: ObjectKaz
- 创建于: 2021-06-24 05:00:20
- 更新于: 2023-05-25 17:17:17
- 链接: https://www.objectkaz.cn/1e06366eacac.html
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。