数据结构考研复习

1. 绪论

1.1 基本概念

基本概念和术语
  1. 数据
  2. 数据元素 一个对象,比如一个学生就是一个数据元素,由学号、姓名、性别等数据项组成。
  3. 数据对象 具有相同性质的数据元素的集合
  4. 数据类型

数据结构三要素

  1. 逻辑结构 ,
    分为线性结构(结构中的数据元素之间只存在一对一的关系)和非线性结构。
  2. 存储结构
    1)顺序存储(逻辑上相连的元素存储在物理位置上也相连的存储单元中)
    2)链式存储
    3)索引存储
    4)散列存储
  3. 运算

1.2 算法

一个算法具有以下5个重要特性:(必须满足)
  1. 有穷性
  2. 确定性
  3. 可行性
  4. 输入
  5. 输出

1.3 例题

1.【真题】 已知两个长度分别为m,n的升序链表,若将他们合并为长度为m+n的一个降序链表,则最坏情况下的时间复杂度为()
A.O(n) B.O(mn) C.O(min(m,n)) D.O(max(m,n))
答案: D

2.下列说法错误的是()
I. 算法原地工作的含义是指不需要任何额外的辅助空间
II. 在相同规模n下,复杂度为O(n)的算法在时间上总是优于复杂度为O(2 n)的算法
A. I   B.II   C. I和II
答案: A

2. 线性表

顺序表线性表
特点表中元素的逻辑顺序与物理顺序相同
存取方式随机存取(存取表中元素时可以随机存取任一元素)非随机存取
优点1.存取速度快O(1)
2.存储密度大,需要大量连续存储单元
1.插入O(1)和删除方便O(n)
(删除主要浪费的时间在查找上)
2.结点空间只需要在申请时分配,操作灵活高效
缺点1.插入删除难O(n)
2.需要预分配足够大的存储空间
查找O(n)

2.1 顺序表

2.2 链式表

2.3 例题

1.【真题】已知一个带有表头结点的单链表,结点结构为 【data|link】
假设该链表只给出了头指针list,在不改变链表的前提下,请设计一个尽可能高效的算法,查找链表中倒数第k个位置上的结点(k为正整数)。若查找成功,则输出data值,返回1;否则只返回0。
思路:定义两个指针p,q初始时均指向头结点的下一个结点,p沿链表移动,当p移动到第k个结点时,q指针开始与p指针同时移动。当p指针移动到最后一个结点时,q指针所指示结点为倒数第k个结点。

3. 栈和队列

栈和队列是操作受限的线性表。

3.1 栈

先进后出
数学性质: n个不同元素进栈,出栈元素不同排列的个数为Cn2n /(n+1)

3.1.1 共享栈

为了更好地利用存储空间,防止上溢

3.2 队列

先进先出

3.2.1 循环队列

队空: Q.front = Q.rear
入队: Q.rear = (Q.rear + 1) % MaxSize
出队: Q.front = (Q.front + 1) % MaxSize
元素个数: (Q.rear - Q.front + MaxSize) % MaxSize
区别队空还是队满:
  1. 牺牲一个单元 (Q.rear + 1) % MaxSize = Q.front

3.2.2 双端队列

在这里插入图片描述

3.3 例题

1.【真题】已知循环队列存储在一维数组A[0…n-1]中,且队列非空时front和rear分别指向队头元素和队尾元素,若初始时队列为空,且要求第一个进入队列的元素存储在A[0]处,则初始front和rear的值分别是()
A.0,0 B.0,n - 1 C.n-1, 0 D. n-1, n-1

解答:因为队列非空时front和rear要指向队头元素和队尾元素,所以在入队后front和rear都要指向A[0],且入队只操作rear = (rear + 1) % n,所以选B

2. 用链式存储方式的队列进行删除操作时需要
A. 仅修改头指针 B.仅修改尾指针 C.头尾指针都要修改 D.头尾指针可能都要修改

解答: 删除元素从表头删除,通常仅需要修改头指针,但若队列中仅有一个元素时,尾指针也需要修改,删除后队列为空,需修改尾指针rear = front,选D

4. 串

4.1 KMP算法

KMP算法分为两步

  1. 获取next数组
  2. 根据next数组对子串进行移动

4.1.1 next数组

next[j] =
  1. 0, j = 1 (模式串中第一个字符(j=1))
  2. s的最长相等前后缀长度+1, 前1~j-1个字符记为s

例如: ‘ababaa’

j123456
ababaa
next[j]011234
void get_next(SString T,int next[] )
{
    int i = 1, j = 0;
    next[1] = 0;
    while(i < T.length)
    {
        if(j == 0 || T.ch[i] == T.ch[j])
        {
            i++;
            j++;
            next[i] = j;
        }else j = next[j];
    } 
}

4.1.2 kmp算法

两个指针p=1,q=1初始指向主串S和子串L的第一个字符,若字符匹配则p++,q++, 若不匹配则子串指针q发生回退,q = next[q]。最终当出现q>L.length时找到匹配子串的第一个字符的位置i = q - L.lenth
int index_KMP(SString S, SString L) // S大字符串,L要查找的字符串
{
   int i = 1,j = 1;
   int next[L.length+1];
   get_next(L, next);
   while(i <= S.length && j <= L.length)
   {
       if(j == 0 || S.ch[i] == L.ch[j])
       {
           i++;
           j++;
       }else j = next[j];
   }
   if(j > L.length) return i - L.length;
   return 0;
}

4.1.3 kmp算法的进一步优化

当出现子串L中的字符L[i] = L[j]时(j > i),next[j] = next[i]
例如: 'aaaab'
j12345
aaaab
next[j]01234
nextval[j]00004
void get_nextval(SString T,int next[] )
{
    int i = 1, j = 0;
    next[1] = 0;
    while(i < T.length)
    {
        if(j == 0 || T.ch[i] == T.ch[j])
        {
            i++;
            j++;
            if(T.ch[i] != T.ch[j]) next[i] = j;
            else next[i] = next[j];
        }else j = next[j];
    } 
}

4.2 例题

1.【真题】设主串T为'abaabaabcabaabc',模式串S='abaabc',采用KMP算法进行模式匹配,到匹配成功为止,在匹配过程中进行的单个字符间的比较次数为______
解答:
j123456
abaabc
next[j]011223
匹配过程分为两步:
  1. 第一步比较了6次,此时在主串的第6个字符,模式串的第6个字符,发生了不匹配,根据next[6] = 3,模式串的指针j跳转到了3
  2. 第二步从主串的第6个字符‘a’和模式串的第3个字符’a’开始进行匹配,匹配了4次,成功找到子串。
    所以答案为10次。

5.树与二叉树

5.1 树的定义

  1. 树中一个结点的孩子个数称为该结点的度,树中结点最大度数称为树的度
  2. 结点的深度是从根结点开始自顶向下逐层累加的
  3. 结点的高度是从叶子结点开始自底向上逐层累加的
  4. 结点个数的计算,若树的度为2,n = n0+n1+n2,且n = 0n0+1n1+2*n2+1,因为所有结点的度+1 = 所有结点个数(根节点没有父结点)

5.2 二叉树

二叉树是有序树
完全二叉树
  1. 若有度为1的结点,则只可能有一个,且该结点只有左孩子无右孩子
  2. 非空二叉树的叶子结点数等于度为2的结点数加1,即n0=n2+1

    证明:设B为分支总数,n为总结点数, n = B + 1, B = n1 + 2n2,n = n0 + n1 + n2
  3. 具有n个结点的完全二叉树的高度为⌈log2(n+1)⌉

    证明:2h-1<n <= 2h -1

5.2.1 二叉树的存储结构

顺序存储结构:适合满二叉树和完全二叉树
一般从数组下标1开始存储树中的结点

在这里插入图片描述

链式存储结构:在含有n个结点的二叉链表中,含有n+1个空链域在这里插入图片描述

5.2.2 二叉树的遍历

  1. 先序遍历: 根左右
  2. 中序遍历: 左根右
  3. 后序遍历: 左右根
    在这里插入图片描述

5.3.3 *线索二叉树

引入线索二叉树的目的就是为了加快查找结点前驱和后继的速度。
将含有n个结点的二叉树中的n+1个空指针用于存放线索。
线索化的过程中若结点没有前驱或者后继也要指向null

中序线索化

在这里插入图片描述
最后一个结点的右孩子指针指向null,rtag=1,用于遍历时判断结点有无右孩子,且中序遍历的最后一个结点一定没有右孩子。
在这里插入图片描述
在这里插入图片描述

先序线索化

先序线索化时由于先对T结点进行了线索化,当PreThread(T->lchild)时会出现,访问T结点的前驱,出现循环,所以要访问T的左孩子结点时要对rtag是否是真的左孩子的判断。(右孩子不用)

在这里插入图片描述
后续线索化在这里插入图片描述

线索二叉树中寻找前驱后继(一般只考察手算)在这里插入图片描述

中序线索二叉树 1. 后继
I.T.rtag == 1,next = T->rchild
II.T.rtag == 0,next = p的右子树的最左下结点![在这里插入图片描述](https://img-blog.csdnimg.cn/20210720143123921.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NldmVuU3Rhcl8x,size_16,color_FFFFFF,t_70)
  1. 前驱
    在这里插入图片描述

先序线索二叉树

  1. 后继在这里插入图片描述
  2. 前驱,若有左孩子,则找不到

后序线索二叉树

  1. 后继,若有右孩子,则找不到
  2. 前驱在这里插入图片描述

5.3 树和森林

5.3.1 树和森林的转换

树的性质:n个结点的树中有n-1条边, 若森林F中有15条边,25个结点,说明森林中有(25-15)=10颗树
树转换为二叉树的规则:每个结点左指针指向它的第一个孩子,右指针指向它的相邻右兄弟

在这里插入图片描述

5.3.2 树和森林的遍历

森林树对应的二叉树的遍历序列
先根遍历
(如上图的先根遍历序列为
ABEFCDG)
先序遍历森林
(依次对各个树先根遍历)
先序遍历
后根遍历
(EFBCGDA)
中序遍历森林
(依次对各个树后根遍历)
中序遍历
后序遍历

5.4 二叉排序树(BST)

5.4.1 二叉排序树的构造

5.4.2 二叉排序树的删除

若被删除结点Z为

  1. 叶结点,直接删除
  2. 结点只有一颗左子树或右子树,让子树成为Z的父结点的子树
    在这里插入图片描述
  3. 有左右两棵子树,令Z的直接后继(或直接前驱)代替Z,然后从二叉排序树中删去这个直接后继,转化为情况1.2在这里插入图片描述

5.4.3 二叉排序树的查找效率

当有序表是静态查找表时,宜用顺序表作为其存储结构,而采用二分查找表实现其查找操作;
当有序表时动态查找表,应选择二叉排序树作为其逻辑结构。
在这里插入图片描述

查找成功的平均查找长度ASLa=(1+2x2+3x4+4x3) / 10 = 2.9
查找失败的平均查找长度ASLa=(3x5+4x6) / 11 = 3.55

5.4.4 *平衡二叉树 AVL树(一般考察选择题,手算)

平衡因子 = 左子树高 - 右子树高
叶子结点没有平衡因子。 定义: 平衡二叉树的平衡因子只可能是0,-1,1

在这里插入图片描述

  1. LL在这里插入图片描述

  2. RR在这里插入图片描述

  3. LR,令最小平衡子树的根节点的左孩子的右孩子先左旋再右旋
    在这里插入图片描述
    在这里插入图片描述

  4. RL在这里插入图片描述
    在这里插入图片描述

5.5 哈夫曼树

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

5.5.1 哈夫曼树的构造

  1. 从权值最小的两个结点

5.6 例题

1.若一颗深度为6的完全二叉树的第6层有3个叶子结点,则该二叉树中共有____个叶子结点。
解答: 第5层共有16个结点,减去有孩子的2个结点,共有14个+3个=17个

2.已知一颗有2011个结点的树,其叶结点个数是116,该树对应的二叉树中无右孩子的结点个数是_____。
解答: 所以答案为1896

在这里插入图片描述
3. 线索二叉树是一种__结构
A.逻辑 B.逻辑和存储 C.物理 D.线性
答案:线索二叉树是加上线索的链表结构,是二叉树在计算机内部的一种存储结构,选C

4. __的遍历仍需要栈的支持
A.前序线索树 B.中序线索树 C.后序线索树 D.所有线索树
解答:后序线索树最后访问根结点,后序线索树不方便访问后继结点,所以还是要用递归即用到栈才能完全遍历。选C

5.【真题】若一棵非空k(k>2)叉树T中的每个非叶结点都有k个孩子,则称T为正则k叉树。请回答:

1)若T有m个非叶结点,则T中的叶结点有多少
2)若T的高度为h(单结点的树高为1),则T的结点数最多为多少个?最少为多少个?
解答:1)B+1 = k*m = m + n0 => n0 = (k-1)m + 1
2) 最多:(1-kh )/(1-k)。 最少 1 +(h-1)k在这里插入图片描述
6.【真题】若将关键字1,2,3,4,5,6,7依次插入初始为空的平衡二叉树T,则T中平衡因子为0的分支结点的个数是 ____。
解答:
在这里插入图片描述

所以是3个

6. 图

线性表可以是空表,树可以是空树,但图不可以是空图。图中不能一个顶点也没有,图的顶点集一定非空,但边集可以为空。

概念:

有向边<v,w>称为从v到w的弧,v称为弧尾,w为弧头。

简单图:

  1. 不存在重复边
  2. 不存在顶点到自身的边

连通图: 无向图中,若从顶点v到w有路径存在,则称v和w是连通的,若图G中任意两个顶点都是连通的,则称图G为连通图。无向图中的极大连通子图称为连通分量。
若一个图有n个顶点,如果边数小于n-1,那么此图必是非连通图。
非连通图最多可以有C2 n-1条边。

强连通图: 有向图中,若从顶点v到w和w到v都有路径存在,则称v和w是强连通的。若图中任意一对顶点都是强连通的,则称此图为强连通图。有向图中的极大强连通子图称为有向图的强连通分量

生成树: 连通图的生成树是包含图中全部顶点的一个极小连通子图。

6.1 图的存储

V为图的顶点数,E为图的边数

邻接矩阵邻接表
确定图中的边数按行按列对每个元素进行检测,时间花费大
删除顶点方便复杂度高
适合图稠密图稀疏图
空间复杂度O(v2)无向图: O(V+E)
有向图:O(V+2E)
唯一性唯一不唯一

在这里插入图片描述
在这里插入图片描述

十字链表
有向图的一种链式存储结构
顶点结构:firstIn、firstOut分别指向以该顶点为弧头或弧尾的第一个弧结点
顶点结构
弧结点:尾域tailvex和头域headvex分别指示弧尾和弧头这两个顶点在图中的位置。链域hlink、tlink分别指向弧头相同和弧尾相同的下一条弧
在这里插入图片描述
在这里插入图片描述


邻接多重表:无向图的另一种链式存储结构

顶点:

  • data:存储此顶点的数据;
  • firstedge:指针域,用于指向第一条依附于该结点的边。

在这里插入图片描述

:

  • mark:标志域,用于标记此结点是否被搜索过
    ivex 和 jvex:数据域,分别存储图中各边两端的顶点所在数组中的位置下标;
    ilink:指针域,指向下一个依附于 顶点ivex 的边 ;
    jlink:指针域,指向下一个依附于 顶点jvex 的边;
    info:指针域,用于存储与该顶点有关的其他信息,比如无向网中各边的权;

在这里插入图片描述
在这里插入图片描述

6.2 图的遍历

广度优先遍历BFS:先访问起始顶点v,从v出发,依次访问v的各个未被访问过的邻接顶点w1,w2,…,wi,再依次访问w1,w2,…wi的未被访问的邻接结点。(队列实现)
在这里插入图片描述
广度优先生成树
在这里插入图片描述
因此访问顺序是:A -> B -> C -> D -> F -> G -> E -> H

深度优先遍历DFS:先访问起始顶点v,从v出发,访问v的未被访问过的邻接顶点w1,再访问w2,的未被访问的邻接结点,重复上述过程,当不能再继续向下访问时,依次退回最近被访问的结点,若它还有没被访问过的邻接结点,重复上述过程。
在这里插入图片描述
因此访问顺序是:A -> B -> G -> E -> C -> D -> H -> F

6.2.1 图的遍历与连通性

  • 无向图:调用BFS/DFS函数次数 = 连通分量数
  • 有向图:对强连通图,只调用1次函数

6.3 最小生成树

最小生成树: 带权图中权值之和最小的生成树。

6.3.1 Prim算法

时间复杂度:O(V2),适用于边稠密的图
初始时从图中任取一个顶点如V1加入树T,之后选择一个当前T中顶点集合距离最小的顶点加入T。
在这里插入图片描述

6.3.2 Kruskal算法

依次选择权值最小的边,
在这里插入图片描述

6.4 最短路径

带权路径长度:顶点v0到顶点v1的一条路径所经过的边的权值之和。

6.4.1 Dijkstra算法求单源最短路径

即求一个顶点到其他顶点的最短路径。

时间复杂度:O(V2)
注意:不适用与边上带负权值的图
在这里插入图片描述

6.4.2 Floyd算法求各个顶点之间的最短路径

时间复杂度:O(V3),允许图中有带负权值的边,但不允许带包含负权值的边组成的回路。
直接看图,更新完后再写邻接矩阵。
依次将各个顶点作为中间结点,重新计算各个顶点之间最短路径。
计算完成后的邻接矩阵A2 即任意顶点之间的最短路径。
在这里插入图片描述

6.5 有向无环图描述表达式

有向无环图: 若一个有向图中不存在环,则称为有向无环图。简称为DAG图。
利用有向无环图对存在重复子式的表达式的优化,节省存储空间。
方法:

  1. 把各个操作数不重复地排成一排
  2. 标出各个运算符顺序
  3. 按顺序加入运算符
  4. 自底向上逐层检查,同层运算合并

6.6 关键路径

AOV网: 若用DAG图表示一个工程,其顶点表示活动,用有向边<Vi, Vj>表示活动Vi必须先于活动Vj进行的一种关系。

6.6.1 拓扑排序

  1. 从AOV网中选择一个没有前驱的顶点输出
  2. 从网中删除该顶点和所有以它为起点的有向边
    在这里插入图片描述

6.6.2 关键路径

在带权有向图中,以顶点表示事件,以有向边表示活动,以边上的权值表示完成该活动的开销,称之为AOE网
源点(开始顶点): AOE网中入度为0的顶点
汇点(结束顶点): AOE网中出度为0的顶点
关键路径:从源点到汇点的所有路径中,具有最大路径长度的路径
关键活动:关键路径上的活动



寻找关键活动(看书p235)

事件最早发生时间ve(k):
从源点开始到vk的最长路径长度

6.7 例题

1.判断有向图中是否存在回路,除可以使用拓扑排序外,还可以利用__
A.求关键路径的方法 B.求最短路径的Dijkstra算法 C.深度优先遍历算法 D.广度优先算法
解答:选C,对顶点v进行深度优先遍历时,出现一条从<u,v>的边则存在回路(把v视为未搜索过)

2.使用DFS算法递归遍历一个无环有向图,并在退出递归时输出相应结点,这样得到的顶点序列是
A.逆拓扑有序 B.拓扑有序 C.无序的 D.都不是
解答:选A

7.查找

7.1 顺序查找

7.2 折半查找

7.3 分块查找

7.4 B树和B+树

7.5 散列表

7.6 例题

1.顺序查找适合于存储结构为__的线性表
A.顺序存储结构或链式存储结构 B.散列存储结构
C.索引存储结构 D.压缩存储结构
解答: 选A。

2.【真题】下列选项中,不能构成折半查找中关键字比较序列的是__
A.500,200,450,180 B.500,450,200,180
C.180,500,200,450 D.180,200,500,450
解答:选A。

  1. 第一次比较500,下次出现的关键字一定x<=500
  2. 第二次比较200,下次出现的关键字一定200<=x<=500
  3. 第三次比较450,下次出现的关键字一定200<=x<=450

8.排序

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值