前言
输出是检验输入的最好方式,也一直想写点博客来输出,但总觉得自己写的内容不够高大上而不了了之(好吧是因为懒),这一次下定决心要写博客了,就从考研复试常考的这些问题开始吧。以下的内容,不一定准确以及完整(毕竟菜狗),但都是经过我的消化并反复检查后输出的内容,希望对正在准备考研复试的你有帮助。
一、绪论
什么是数据结构
数据结构是指相互之间存在一种或多种关系的数据元素的集合
数据的逻辑结构
数据的逻辑结构是对数据之间关系的描述,与存储结构无关,一种逻辑结构可有多种存储结构;通常有四类:
(1)集合
(2)线性结构(一对一)
(3)树形结构(一对多)
(4)图状结构(多对多)
简要说明数据的存储(物理)结构
(1)顺序存储:逻辑上相邻的元素物理位置也相邻
(2)链式存储:不要求逻辑上相邻的元素物理位置也相邻,通过结点附加的指针找到下一个结点
(3)索引存储:建立附加的索引表来标识结点的地址
(4)散列存储:根据结点的关键字通过散列函数计算出结点的地址
二、线性表、栈、队列
顺序表和链表的比较
(1)顺序表根据线性表中的元素逻辑顺序将元素存储到一块连续的空间中;链表则将元素存储到结点中并用指针指出结点间的逻辑关系,不一定要存储在一块连续的空间;
(2)顺序表支持随机存取;链表则需要从头结点遍历
(3)顺序表插入和删除需要移动大量元素;链表则只需要修改指针
为什么对单链表设置头节点?
(1)保证每一个结点都有前驱结点,使得插入和删除结点的处理统一
(2)带头结点的链表,在表空时存在头结点,使得空表和非空表的处理统一
(3)带头结点的链表可以在头结点数据域中存放一些信息,如结点的个数
头指针、头结点和首元结点的区别
(1)头指针是指向链表第一个结点的指针,是链表存在的标志
(2)首元结点是链表中存储线性表的第一个结点
(3)头结点是首元结点的前一个结点,是为了使得对链表的处理统一而设置的结点
栈的用途?队列的用途?
栈可用于函数调用和递归,括号匹配,后缀表达式求值;队列常用于计算机各种资源的管理,消息缓冲器的管理和广度有限搜索算法等
栈在括号匹配中的算法思想
遍历表达式,缝左括号就入栈,遇到右括号则检查栈是否为空,为空则表明不匹配,不为空则将左括号出栈;表达式遍历完成后栈为空则表明匹配,若栈中还有左括号表明不匹配
栈在后缀表达式求值的算法思想
(1)是操作数则进栈
(2)是运算符则将两个元素出栈并将得到的结果进栈
(3)表达式扫描完成后,栈顶元素为所求结果
队列的溢出现象?解决办法?
下溢现象:队列为空时出队产生的现象;是正常现象;
真上溢现象:队列满时继续往进队;建立一个足够大的存储空间来解决;
假上溢现象:队列未满而无法继续进队;采用循环队列来解决;
三、树与二叉树
什么是树?
树是一种非线性的数据结构,其元素之间有明显的层次关系,由结点和边组成且不存在环;在树的结构中,每个结点都只有一个前件称为父结点,没有前件的结点为树的根结点,简称为树的根;每个结点可以有多个后件成为结点的子结点,没有后件的结点称为叶子结点。
树的存储结构,二叉树的存储结构
树的存储结构,常用的有两种:
(1)双亲存储结构(顺序存储):用数组来存储,数组下标表示树的结点,数组元素的内容表示该结点的双亲结点;
(2)孩子兄弟存储结构(链式存储):用二叉链表存储树,结点中一个指针指向自己的孩子,另一个指针指向自己的兄弟;
(3)孩子表示法(链式存储):每个结点的孩子结点用单链表连接起来;二叉树的存储结构,常用的有两种:
(1)顺序存储结构:先将二叉树补充为完全二叉树,再将树的值依次存入一个一维数组中;适用于完全二叉树,存储一般的树会浪费大量存储空间
(2)链式存储结构:采用二叉链表,左指针指向左孩子,有指针指向右孩子,数据域存储对应的数据元素
度为2的树与一棵二叉树有何区别
(1)度为2的树要求树中最少有一个结点的孩子数为2,二叉树则只要求度不超过2即可
(2)二叉树子树区分左右,度为2的树则不区分
满二叉树,完全二叉树,二叉排序树,平衡二叉树特性
满二叉树:每一层的结点数达到最大值
完全二叉树:除最后一层外每一层的结点数达到最大值且最后一层若有缺失结点也是从右往左缺失
二叉排序树:左子树结点中的值都小于结点的值,结点的值都小于右子树的值
平衡二叉树:在二叉排序树的基础上,保证了左右子树的高度之差的绝对值不大于1
什么是线索二叉树?优点?
由二叉链表存储的二叉树,n个结点有n+1个空链域,将这些空链域利用起来正是线索二叉树;
其优点是能够较快地找到当前结点的前驱和后继结点
什么是哈夫曼树?简述如何构造
哈夫曼树带权路径最短(带权路径:树中结点的值乘于结点到根的距离)
从集合中选取根结点权值最小的两棵树(集合中的树一开始都是结点)组成一颗新树,新树的权值为左右子树权值之和,删除集合选取的两个结点,增加新树的结点,重复上述操作;
四、图
图的存储结构
邻接矩阵(顺序存储结构):矩阵的行数或列数表示顶点数,矩阵元素来表示边的情况;
邻接表(链式存储结构):对每个顶点建立一个单链表,每个单链表第一个结点存放有关顶点的信息,其余结点存放有关边的信息
简述深度优先搜索遍历及广度优先搜索遍历的思想
深度优先搜索:从某个顶点出发,首先访问这个顶点并设为已访问,然后访问该顶点的未被访问的邻接结点,重复此操作直到某一结点的所有邻接点都已被访问,此时退回上一步继续访问其他未被访问的邻接点直到遍历完成;
广度优先搜索:从某个顶点出发,访问其所有邻接结点并设为已访问,然后按照访问的顺序访问邻接结点的邻接结点直到遍历完成
如何判断有向图是否有环
两种方法:
(1)深度搜索遍历:若图中有一个顶点被访问两次则证明有环
(2)拓扑排序:查找图中入度为0的顶点,删除它,重复此操作;若图中最后还剩顶点则证明有环
最小生成树是什么?用途?
连接图的各个顶点且边的权值之和最小的是最小生成树;
重要用途,如设计通信网。设图的顶点表示城市,边表示两个城市之间的通信线路,边的权值表示建造通信线路的费用。n个城市之间最多可以建n(n-1)/2条线路,用最小生成树来选择其中的n-1条,使总的建造费用最低
简述最小生成树两种生成算法
Prim(普里姆):采用了贪心算法的思想
(1)将起始顶点并入生成树
(2)将各顶点到生成树距离最短的那个顶点并入生成树
(3)更新各顶点到生成树的距离(比较第二步并入的顶点到各顶点的距离是否会比原顶点距离短,会的话则更新顶点到生成树的距离)
(4)重复以上三步直到所有顶点并入,此时最小生成树完成
Kruskal(克鲁斯卡尔):
将连通网中所有的边按照权值大小做升序排序,从权值最小的边开始选择,只要此边不和已选择的边一起构成环路,就可以选择它组成最小生成树。对于 N 个顶点的连通网,挑选出 N-1 条符合条件的边,这些边组成的生成树就是最小生成树。
通常用并查集来判断已选边是否构成回路(若待加边的两个顶点同属一个集合则构成回路,不同属则将边的一个顶点加入另一个顶点的集合中,完成加边)
tips: 可以用Kruskal的英文比Prim长来记忆,长的是加边,短的是加点
什么是并查集
并查集是一种维护集合的数据结构,支持合并和查找两种操作;
合并:合并两个集合;
查找:判断两个元素是否在一个集合中;
并查集是用数组来实现的,设数组 int father[N] ,其中 father[i] 表示元素 i 的父亲结点,另外如果father[i] = i 则表示元素 i 是该集合的根结点
例如 father[2] = 1 表示元素 2 的父结点为 1;father[1] = 1 表示该集合的根结点为 1;
比较AOV网与AOE网
相同点:
两者都是有向无环图
不同点:
AOV网:顶点表示活动,边表示活动之间的先后关系,一般用来表示活动的制约关系;
AOE网:边表示活动,边的权值表示活动持续时间,顶点用来表示活动的开始,一般用来分析工程最少需要多少时间完成,或者是工程为缩短时间可以加快哪些活动;
关键路径和关键活动
在AOE网中,从源点到汇点的路径中的最长路径为关键路径,完成整个工期所需要的最短时间就是关键路径长度所代表的时间。关键路径上的活动又称为关键活动
最短路径的算法
Djikstra(迪杰斯特拉)
从源点出发,每次选择离源点最近的一个顶点前进,然后以该顶点为中心进行扩展,最终得到源点到其余所有点的最短路径。
Floyd(佛洛依德)
a.从任意一条单边路径开始。所有两点之间的距离是边的权,如果两点之间没有边相连,则权为无穷大。
b.对于每一对顶点 u 和 v,看看是否存在一个顶点 w 使得从 u 到 w 再到 v 比己知的路径更短。如果是更新它。
(1)Dijkstra算法适用稠密图(邻接矩阵),因为稠密图问题与顶点关系密切;Floyd稠密图、稀疏图都适用;
(2)Dijkstra不能处理负权图,Flyod能处理负权图;
(3)Dijkstra处理单源最短路径,Flyod处理多源最短路径;
五、查找与排序
排序算法的稳定性
排序前后关键字的先后次序是否发生改变,如果改变了就是不稳定的算法,没改变就是稳定的算法;
在天勤上看到的助记口诀:“考研压力大,心情不稳定,快些选堆朋友来聊天”
快----快速排序;些----希尔排序(谐音);选----选择排序;堆----堆排序;这些排序是不稳定的
稳定算法的口诀:
插入奇数个泡泡,然后将他们归并起来;插(插入)奇(基数排序)泡(冒泡排序)归(归并排序)
时间复杂度为 O(nlogn)的排序方法?
在天勤上看到的助记口诀:
军训排队时,教官说:快些以nlogn的速度归队;快(快速),些(希尔),归(归并),队(堆)
B树(B-树)与B+树的不同点
(1)B树n个结点有n+1个分支,B+树n个结点有n个分支
(2)B树的每个结点包含信息,B+树非叶结点起索引作用,只有叶子结点包含信息(且包含了全部关键字)
(3)B+树有一个指针指向关键字最小的叶子结点,所有叶子结点链接成一个链表,B树没有
(4)B树和B+树每个结点的关键字个数取值范围不同;
什么是散列表
散列表根据关键字来计算出关键字在表中的地址,用来加快查找的速度;
决定散列表ASL(平均查找长度)的因素
(1)选用的散列函数
(2)选用的冲突处理方法
(3)散列表的饱和程度
Hash函数构造方法,冲突处理方法
函数构造方法:(1)除留余数法(2)直接定址法
冲突处理方法:(1)线性探查法(2)平方探查法(3)链地址法
排序算法
排序:是指把一个任意元素的序列排列成一个按关键字key有序的序列。内部排序包括:插入排序、选择排序、交换排序、归并排序、基数排序。其中插入排序包括:直接插入排序、折半插入排序、希尔排序;选择排序包括:简单选择排序,堆排序;交换排序包括:冒泡排序、快速排序。
(1)直接插入排序(稳定):基本思想为:将序列分为有序部分和无序部分,从无序部分依次选择元素与有序部分比较找到合适的位置,将原来的元素往后移,将元素插入到相应位置上。时间复杂度为:O(n^2),空间复杂度为O(1)
(2)折半插入排序(稳定):基本思想为:设置三个变量low high mid,令mid=(low+high)/2,若a[mid]>key,则令high=mid-1,否则令low=mid+1,直到low>high时停止循环,对序列中的每个元素做以上处理,找到合适位置将其他元素后移进行插入。他的比较次数为O(nlog2n),但是因为要后移,因此时间复杂度为O(n^2),空间复杂度为O(1)。 优点是:比较次数大大减少。
(3)希尔排序(不稳定):基本思想为:先将序列分为若干个子序列,对各子序列进行直接插入排序,等到序列基本有序时再对整个序列进行一次直接插入排序。优点是:让关键字值小的元素能够很快移动到前面,且序列基本有序时进行直接插入排序时间效率会提升很多,空间复杂度为O(1)。
(4)简单选择排序(不稳定):基本思想为:将序列分为2部分,每经过一趟就在无序部分找到一个最小值然后与无序部分的第一个元素交换位置。优点是:实现起来特别简单,缺点是:每一趟只能确定一个元素的位置,时间效率低。时间复杂度为O(n^2),空间复杂度为O(1)。
(5)堆排序(不稳定):设有一个任意序列,k1,k2,…,kn,当满足下面特点时称之为堆:让此序列排列成完全二叉树,该树具有以下特点,该树中任意节点均大于或小于其左右孩子,此树的根节点为最大值或者最小值。优点是:对大文件效率明显提高,但对小文件效率不明显。时间复杂度为O(nlog2n),空间复杂度为O(1)。
(6)冒泡排序(稳定):基本思路为:每一趟都将元素进行两两比较,并且按照“前小后大”的规则进行交换。优点是:每一趟不仅能找到一个最大的元素放到序列后面,而且还把其他元素理顺,如果下一趟排序没有发生交换则可以提前结束排序。时间复杂度为O(n^2),空间复杂度为O(1)。
(7)快速排序(不稳定):基本思路为:在序列中任意选择一个元素作为中心,比它大的元素一律向后移动,比它小的元素一律向前移动,形成左右两个子序列,再把子序列按上述操作进行调整,直到所有的子序列中都只有一个元素时序列即为有序。优点是:每一趟不仅能确定一个元素,时间效率较高。时间复杂度为O(nlog2n),空间复杂度为O(log2n).
(8)归并排序(稳定):基本思想为:把两个或者两个以上的有序表合并成一个新的有序表。时间复杂度为O(nlogn),空间复杂度和待排序的元素个数相同。
(9)基数排序:时间复杂度为:对于n个记录进行链式基数排序的时间复杂度为O(d(n+rd)),其中每一趟分配的时间复杂度为O(n),回收的时间复杂度为O(rd)。