2021计算机考研408数据结构个人笔记

目录

本笔记为博主2021计算机专业考研408科目的数据结构个人笔记,由于本来就具有一定的数据结构经验(毕竟也是计院人),所以笔记是十分简要的,仅供参考。

杂项


逻辑结构

线性结构

  1. 顺序表
  2. 队列

非线性结构

  1. 集合
  2. 树形结构
  3. 图状结构

存储结构(物理结构)

  1. 顺序存储
  2. 链式存储
  3. 索引存储
  4. 散列存储(哈希存储)

线性表


顺序表(数组)

  • 逻辑结构:线性表
  • 存储结构:顺序存储

链表

  • 逻辑结构:线性表
  • 存储结构:链式存储

单链表、双链表

循环单链表、循环双链表

静态链表

借助数组来表述链表,链表指针即结点相对地址(数组下标)。

下标 元素 指针
0 头结点 2
1 b 3
2 a 1
3 c -1
4 - -

  • 逻辑结构:线性表(限定操作)
  • 排列个数:n个不同元素进栈,出栈元素不同排列的个数为\(\frac{1}{n+1}C^{n}_{2n}\)
  • 应用:括号匹配、算术表达式(中缀转后缀)、递归转非递归、DFS

顺序栈

  • 存储结构:顺序存储

链栈

  • 存储结构:链序存储

共享栈

  • 顺序栈的双向存储

队列

  • 逻辑结构:线性表(限定操作)
  • 应用:层序遍历、BFS

循环队列

  • 存储结构:顺序存储

链式队列

  • 存储结构:链式存储

双端队列

  • 存储结构:顺序存储、链式存储

需会判断序列是否满足题设条件(输入受限、输出受限)

多维数组(矩阵)

压缩存储

  • 对称矩阵:存储对角线和一个三角区的元素
  • 三角矩阵:存储对角线和一个三角区的元素
  • 三对角矩阵:存储三条对角线的元素

稀疏矩阵

将非0元素及其对应行和列构成三元组,可用以下方法存储这些三元组:

  • 采用数组存储
  • 采用十字链表法


串的存储方式

  • 定长顺序存储
  • 堆分配存储
  • 块链存储

暴力模式匹配算法

  • 时间复杂度:\(O(mn)\)

KMP算法

  • 时间复杂度:\(O(m+n)\)
  • 优势:不回溯主串指针

构造next数组

  • s为空时,最长相等前后缀长度 = -1
  • s为单个字符时,前缀为空,后缀为空,最长相等前后缀长度 = 0
  • s为'ab'时,前缀为a,后缀为b,最长相等前后缀长度 = 0
  • s为'aba'时,前缀为a、ab,后缀为ba、a,最长相等前后缀长度 = 1
  • next[k] = s[1~k-1]的最长相等前后缀长度。

例如:对s[1~5] = 'abcac',next[4] = s[1~3]的最长相等前后缀长度。

编号 1 2 3 4 5
模式 a b c a c
next -1 0 0 0 1

为了方便计算,也可让next数组元素均+1(方便直接索引):

编号 1 2 3 4 5
模式 a b c a c
next 0 1 1 1 2

next数组构造实现:

int i=1,j=0;
next[1] = 0;
while(i<m){
    if(j==0||p[i]==p[j]){
        ++i;++j;
        next[i] = j;
    }
    else{
        j=next[j];
    }
}

匹配过程

  1. 设置双指针:i指针用于遍历主串,j指针用于遍历模式。
  2. 当s[i]==p[j],则i++,j++;若匹配失败,i指针不用回退,j指针则回退至next[j]位置。
  3. 若j先达到模式尾,证明匹配成功。若i先到达主串尾,证明匹配失败。

构造nextval数组

可能出现连续多次匹配失败,模式指针多次回退相同字符的情况:

j 1 2 3 4 5 6 7 8 9
主串 a a a b a a a a b
模式 a a a a b
next[j] 0 1 2 3 4
nextval[j] 0 0 0 0 4

构造next数组时,加入判断:

if(p[i]!=p[j]) nextval[i] = j;
else nextval[i] = nextval[j];   //相同字符,因此i失败时可以回退到nextval[j]的位置


树的性质

度:

  • 结点的度 = 该结点的孩子个数
  • 树的度 = 树中结点的最大度数
  • 树的结点数 = 所有结点的度数 + 1
  • 二叉树使用二叉链表存储:n个结点有n+1个空指针
  • AVL深度h最低数量的结点:N(h) = 1 + N(h-1) + N(h-2); N(0)=1, N(1)=1

路径:

  • 路径:树中某两个节点之间所经过的节点序列构成
  • 路径长度:路径上所经过的边的个数
  • 树的路径长度:树根到各个节点的路径长度之和

二叉树的遍历方式(前序、中序、后序、层序)

  • 前序遍历:注意非递归实现
  • 中序遍历:注意非递归实现
  • 后序遍历:注意非递归实现
  • 层序遍历
  • 遍历序列构造二叉树:中序序列和(前序序列|后序序列|层序序列)可以唯一确定一棵二叉树。

线索二叉树

利用传统二叉树的空指针,指向遍历前驱或后驱的结点,从而加快查找前驱或后驱结点和遍历的速度。

  • 需要引入2个额外标记位
class Node{
    Node* lchild;
    int ltag;       //若为0,lchild表示结点左孩子。若为1,表示前驱结点。
    Node* rchild;
    int rtag;       //若为0,rchild表示结点右孩子。若为1,表示后继结点。
    Data data;
};

中序线索二叉树、前序线索二叉树

  • 构造
  • 找结点前驱和后继

后序线索二叉树

  • 构造:使用三叉链才可支持找后驱,否则需借助栈的支持才可找后驱
  • 找结点前驱和后继

排序二叉树、平衡二叉树

排序二叉树

  • 查找最坏时间复杂度:\(O(n)\) (最坏情况为退化成一条链表)

平衡二叉树

  • 查找时间复杂度:\(O(nlogn)\)
  • 平衡因子:左子树与右子树的高度差(注意不是数量差)
  • h层深度的平衡二叉树最少结点数 \(n_h=n_{h-1}+n_{h-2}+1\)(其中\(n_0=0,n_1=1\))
2021计算机考研408数据结构个人笔记2021计算机考研408数据结构个人笔记2021计算机考研408数据结构个人笔记2021计算机考研408数据结构个人笔记

哈夫曼树

带权路径长度

  • 结点的带权路径长度:从树根到结点的路径长度(经过的边数)与该结点上权值的乘积。
  • 树的带权路径长度:所有叶结点的带权路径长度之和。

哈夫曼编码

  • 哈夫曼编码:没有一个编码是另一个编码的前缀

构造哈夫曼树

2021计算机考研408数据结构个人笔记

每次选取两个最小权值的结点,生成一个父结点,其权值为两子节点权值相加;重复直到生成最后一个父结点。

哈夫曼树带权路径长度 = 所有叶结点的带权路径长度之和 = 所有非叶节点的权值之和

B树(多路平衡查找树)

2021计算机考研408数据结构个人笔记

一棵m阶(最多m棵子树,即最多m-1个关键字)B树:

  1. 所有非叶节点至少有\(\lceil{m/2}\rceil\)棵子树,即至少有\(\lceil{m/2}\rceil-1\)个关键字(根节点不算入此规则)
  2. 树所有结点的平衡因子均等于0
  3. 所有叶节点为寻找失败的情况,但是不算入B树的高度

注意插入、删除过程

支持随机访问(从根节点开始向下找),但不支持顺序查找

B+树

2021计算机考研408数据结构个人笔记

一棵m阶B+树(最多m棵子树,即最多m个关键字):

  1. 所有非叶节点至少有\(\lceil{m/2}\rceil\)棵子树,即至少有\(\lceil{m/2}\rceil\)个关键字。(根节点不算入此规则)
  2. 树所有结点的平衡因子均等于0
  3. 非叶节点仅有索引作用,标识其中子结点中最大(或最小)关键字以表示范围。
  4. 叶节点才包含信息,且额外用一条链将所有叶节点链接起来(优势:天然有序,可直接遍历...)

树和森林

树的存储结构

  • 双亲表示法:每个结点用1个指针指向双亲结点。
  • 孩子表示法:每个结点用n个指针指向n个孩子。
  • 孩子兄弟表示法(二叉树表示法):第一个指针指向第一个孩子,第二个指针指向下一个兄弟

与二叉树的转换

2021计算机考研408数据结构个人笔记

树与森林的遍历方式(先根遍历、后根遍历)

  • 先根遍历:对应二叉树形式的先序遍历
  • 后根遍历:对应二叉树形式的中序遍历

并查集

  • Union操作
  • Find操作


图的性质

  • 完全图(简单完全图):无向完全图拥有n(n-1)/2条边。有向完全图拥有n(n-1)条弧
  • 极大连通子图:保持图连通且包含所有边的子图
  • 极小连通子图:保持图连通且边数量最少的子图
  • 连通图(无向图情况):任何顶点之间都有路径可以到达的图
  • 连通分量(无向图情况):每个极大连通子图都是该图的一个连通分量
  • 强连通图(有向图情况):任何顶点之间相互都有路径可以到达的图
  • 强连通分量(有向图情况):每个极大强连通子图都是该图的一个强连通分量(特殊地,单个结点也可为一个强连通分量)
  • 生成树:包含图中所有顶点的极小连通子图
  • 生成森林:图中所有连通分量的生成树
  • 简单路径:顶点不重复出现的路径
  • 简单回路:除了第一个顶点和最后一个顶点,其余顶点不重复出现的回路
  • 有向树:一个顶点入度为0、其余顶点入度均为1的有向图
  • 有向图的度:分为入度和出度
  • 无向图的度:只有单个度

图的存储方式

邻接矩阵法

  • 空间占用:\(O(|V|^2)\)
  • 无向图的邻接矩阵是对称矩阵,可以用压缩存储。

邻接表法

  • 空间占用:无向图为\(O(|V|+2|E|)\),有向图为\(O(|V|+|E|)\)

邻接多重表(无向图)

class Vertex{
    int data;
    Edge* firstEdge;
}
//顶点i和j的边
class Edge{
    int ivex;       //顶点i的位置
    Edge* ilink;    //i的下一个边
    int jvex;       //顶点j的位置
    Edge* jlink;    //j的下一个边
};

2021计算机考研408数据结构个人笔记

十字链表(有向图)

class Vertex{
    int data;
    Edge* firstEdge;
}
//顶点i和j的边
class Edge{
    int ivex;       //顶点i的位置
    Edge* ilink;    //i为边入口的下一个边
    int jvex;       //顶点j的位置
    Edge* jlink;    //j为边出口的下一个边
};

图的十字链表表示不是唯一的,但一个十字链表表示可以确定一个图。

2021计算机考研408数据结构个人笔记

深度优先遍历、广度优先遍历

深度优先遍历(DFS)

使用邻接矩阵:

  • 时间复杂度:\(O(|V|^2)\)
  • 空间复杂度:\(O(|V|)\) (必须递归空间)

使用邻接表:

  • 时间复杂度:\(O(|V|+|E|)\)
  • 空间复杂度:\(O(|V|)\) (必须递归空间)

应用:

  • 可用DFS遍历得到生成树

广度优先遍历(BFS)

使用邻接矩阵:

  • 时间复杂度:\(O(|V|^2)\)
  • 空间复杂度:\(O(|V|)\) (必须借助队列)

使用邻接表:

  • 时间复杂度:\(O(|V|+|E|)\)
  • 空间复杂度:\(O(|V|)\) (必须借助队列)

应用:

  • 可用BFS求解单源最短路径问题(只允许权值相等)
  • 可用BFS遍历得到生成树

Prim算法(最小生成树)

  • 每次选择权值最小边对应的顶点。
  • 时间复杂度:\(O(|V|^2)\),适用边稠密的图

Kruskal算法(最小生成树)

  • 每次选权值最小边。使用 堆 存放边的集合,可将选择最小边时间降为\(O(\log_{2}|E|)\)
  • 时间复杂度:\(O(|E|\log_{2}|E|)\),适用边稀疏顶点较多的图

Dijstra算法(单源最短路径)

  • 每次选取边权值+结点已有代价之和最低的边,并设置对应目标点代价。重复直到所有点顶点都已被设置。
  • 时间复杂度:\(O(|V|^2)\)
  • 注意:不允许边带负权值。

Floyd算法(多源最短路径)

\(A^{(-1)}[i][j] = arcs[i][j]\)

\(A^{(k)}[i][j] = Min\{A^{(k-1)}[i][k]+ A^{(k-1)}[k][j]\}\)

(\(k=0,1,..,n-1\))

计算\(A^{(-1)},A^{(0)},...,A^{(n-1)}\),\(A^{(k)}\)

  • 时间复杂度:\(O(|V|^3)\)
  • 注意:允许带负权值,但不允许有包含负权值边组成的回路。
for(int k = 0;k<n;++k)
for(int i = 0;i<n;++i)
for(int j = 0;j<n;++j)
if(A[i][j] > A[i][k]+A[k][j])
A[i][j] = A[i][k] + A[k][j];

有向无环图描述表达式

相同子式的共享:
2021计算机考研408数据结构个人笔记

拓扑排序(AOV网)

每次选择入度为0的点,选择后删除该点和以它为起点边(使相连的其他点入度-1),然后进行下一轮选择。

  • 时间复杂度:\(O(|V|+|E|)\)
  • 逆拓扑排序:与拓扑排序类似,但选择的为出度为0的点。

关键路径(AOE网)

  • 事件\(v_k\)(点)最早发生时间:\(ve(k)=Max\{ve(j)+Weight(v_j,v_k)\}\)
  • 事件\(v_k\)(点)最迟发生时间:\(vl(k)=Min\{vl(j)-Weight(v_k,v_j)\}\)
  • 活动\(a_k\)(边)最早开始时间:\(e(i) = ve(k)\)
  • 活动\(a_j\)(边)最晚开始时间:\(l(i) = vl(j)-Weight(v_k,v_j)\)
  • 一个活动\(a_i\)最迟开始时间与最晚开始时间差额 \(d(i)=l(i)-e(i)\) 若为0,则该活动为关键活动。

2021计算机考研408数据结构个人笔记

关键路径:

  • 完成整个工程最短时间就是关键路径的长度。
  • 关键路径上的所有活动(边)都是关键活动。
  • 关键路径并不一定唯一(但长度都是工程最短时间)。对于多条关键路径的AOE网,只加快一条关键路径是不会缩短工期的,只有加快全部关键路径才能达到缩短工期的目的。

查找

顺序查找

  • 无序表
  • 有序表(可减少失败平均比较次数,但成功平均比较次数与无序表相等)

折半查找

  • 有序表
  • 判定树:平衡二叉树,做某些判断题需要编排序号模拟下标

分块查找

  • 索引表 + 查找表:先在索引表(块间有序)查找,再在查找表(块内无序)查找

散列结构


散列函数(哈希函数)

装填因子:\(a=\frac{表中记录数n}{散列表长度m}\)

开放定址法

\(H_i=(H(key) + d_i)\%m\)

  • 线性探测法:\(d_i = 0,1,2,...,m-1\);可能发生聚集现象,导致查找效率降低。
  • 平方探测法:\(d_i = 0^2,1^2,-1^2,2^2,-2^2,..,k^2,-k^2\);可有效避免聚集现象。
  • 再散列法:利用第二个散列函数再计算\(H_i=(H(key) + i*H_2(key))\%m\)
  • 伪随机法

拉链法

排序


  • 稳定排序:插入、冒泡、归并、基数
  • 不稳定排序:希尔、选择、快速、堆排
  • 时间复杂度与初始排列状态有关:插入、希尔、冒泡、快速

直接插入排序

  • 时间复杂度:平均\(O(n^2)\),最好\(O(n)\)
  • 空间复杂度:\(O(1)\)
  • 稳定

折半插入排序

相比直接插入排序,只是减少了比较元素的次数,约为\(O(n\log_{2}n)\)

  • 时间复杂度:平均\(O(n^2)\),最好\(O(n)\)
  • 空间复杂度:\(O(1)\)
  • 稳定

希尔排序

通过增量划分子数组,然后使用插入排序算法分别排序,最后整体得到基本有序的数组,整体再用一次插入排序算法。

  • 时间复杂度:平均约为\(O(n^{1.3})\),最坏\(O(n^2)\)
  • 空间复杂度:\(O(1)\)
  • 不稳定

冒泡排序

注意需设置flag,如果一趟排序中没有发生交换,则可以提前终止排序。

  • 时间复杂度:\(O(n^2)\)
  • 空间复杂度:\(O(1)\)
  • 稳定

简单选择排序

  • 时间复杂度:\(O(n^2)\)
  • 空间复杂度:\(O(1)\)
  • 不稳定

快速排序

  • 时间复杂度:平均\(O(n\log_{2}n)\),最坏\(O(n^2)\)
  • 空间复杂度:平均\(O(\log_{2}n)\),最坏\(O(n)\) (即取决于递归的栈空间)
  • 不稳定

划分:首先左指针指向枢纽元,轮流使用右/左指针,每轮只让其中一个指针移动到第一个不符合区间条件的位置,然后左右指针指向的值(总有一个指向枢纽元)交换,下一轮使用另一个指针。

堆排序

  • 时间复杂度:\(O(n\log_{2}n)\)
  • 空间复杂度:\(O(1)\)
  • 不稳定

堆操作:

  • 堆构造(自底向上选择非叶节点,选择后自顶向下更新) 时间复杂度:\(O(n)\)
  • 堆插入(自底向上) 时间复杂度:\(O(\log_{2}n)\)
  • 堆顶删除(自顶向下) 时间复杂度:\(O(\log_{2}n)\)

归并排序

  • 时间复杂度:\(O(n\log_{2}n)\)
  • 空间复杂度:\(O(n)\)
  • 稳定

基数排序

需借助r个辅助存储队列,进行d趟分配和收集。

  • 时间复杂度:\(O(d(n+r))\)
  • 空间复杂度:\(O(r)\)
  • 稳定

多路归并排序(外部排序)

败者树

2021计算机考研408数据结构个人笔记

  • 败者树是一棵完全树,有2k个结点(k为路数),其中k个结点存储胜败者信息,k个结点存储有序路的索引
  • 根节点为胜者,其余非叶结点为败者。
  • 更新后,需要自下往上重新比较胜负者,从而更新败者树。

生成初始归并段

根据可用内存区大小,来对同等大小的记录集进行排序,生成长度一样的初始归并段。

多趟归并排序

例子,2路归并:

2021计算机考研408数据结构个人笔记

在k路归并中,归并趟数为S,初始段记录数量为r

  • 所需内存缓冲区:k个输入缓冲区,1个输出缓冲区(大小不一定与输入缓冲区一致,例如只占1个记录)
  • 直接比较:
    • 每次比较需 \(k-1\) 次
    • \(总比较次数 = S(n-1)(k-1) = \lceil{log_{k}r}\rceil(n-1)(k-1)\)
  • 败者树法:
    • 每次比较只需 \(\lceil{log_{2}k}\rceil\) 次
    • \(总比较次数 = S(n-1)\lceil{log_{2}k}\rceil = \lceil{log_{k}r}\rceil(n-1)\lceil{log_{2}k}\rceil =(n-1)\lceil{log_{2}r}\rceil\)

置换-选择排序(生成不等长度初始归并段)

  1. 先读入一个记录作为初始段的第一个元素。
  2. 每次读入一个记录到内存工作区,若有MINIMAX值(即比输出初始段的末尾值还大),则该记录添入到初始端文件尾,并从内存工作区中移除。
  3. 当内存工作区满额且无MINIMAX值时,则认为完成一个初始段生成。

2021计算机考研408数据结构个人笔记

最佳归并树(不等长度归并段多趟归并排序)

  • 类似k阶哈夫曼树
  • 若结点有n个,\((n-1)\%(k-1)=u\neq 0\),则证明有u个多余结点,需要添加 k-u-1 个权值(长度)为0的虚段

1个完整哈夫曼树 + u个多余结点 + k-u-1个虚段 = 新的1个完整哈夫曼树

2021计算机考研408数据结构个人笔记

上一篇:408笔记--数据结构


下一篇:2021计算机考研408计算机组成原理个人笔记