前言
根据2022年真题,和历年真题编写,主要用于自我复习使用,非建议。
数据结构
选择1-时间复杂度
对于递归函数的时间复杂度计算要多加注意
- 2012年考察过递归的时间复杂度
- 斐波那契递归算法的时间复杂度
朴素递归,其他有优化的斐波那契算法过于复杂,考试第一题一般不会出
int fib(int n) {
if (n < 1) {
return 0;
} else if (n <= 2) {
return 1;
} else {
return fib(n - 1) + fib(n - 2);
}
}
时间复杂度O(2^n)
2. 简单递归函数
n = 1, T(n) = 1;
n > 1. T(n) = 2 * T(n / 2) + n;
题:简单起见,设n是2的整数次幂
n = 2 k n = 2^k n=2k
T ( n ) = T ( 2 k − 1 ) + 2 k = 2 k T ( 2 0 ) + k ∗ 2 k T(n) = T(2^{k-1}) + 2^k = 2^{k}T(2^{0}) + k*2^{k} T(n)=T(2k−1)+2k=2kT(20)+k∗2k
将k换回n
T ( n ) = n ( l o g 2 n + 1 ) T(n) = n(log2n+1) T(n)=n(log2n+1)
时间复杂度O(nlog2n)
3.简单循环程序
按循环次数老实判断,2022年408第一题迷惑性还是很高的。
选择2-栈或者队列
选择3-二叉树、树、森林
选择4-并查集
并查集常见应用
- 克鲁斯卡尔求最小生成树
- 求无向连通图的连通分量
- 判断无向连通图的连通性
选择5-红黑树
- 记忆:“”左根右、根叶黑、不红红、黑路同“
- 时间复杂度
- 删除O(nlog2n)
- 插入O(nlog2n)
- 查找O(nlog2n)
- 在一棵红黑树中,如果所有结点都是黑的,那么它的形态一定是满二叉树
- 根节点黑高为h,关键字最少有 2 h − 1 2^{h}-1 2h−1
- 最多有 2 2 h − 1 2^{2h}-1 22h−1
- n个关键字的红黑树,高度不超过 2 l o g 2 ( n + 1 ) 2log2(n+1) 2log2(n+1)
- AVL树的查找效率通常会稍微好一点,因为红黑树是一种相对平衡
选择6-图的概念
选择7-图的应用
- 最短路
- Dijkstra 单源最短路,不适合负边权
- Floyd 各顶点之间的最短路,允许负边权,但不允许带负权值的边的回路
- 广度优先搜索查找最短路,主要是对无权图和等权图
以上就可以考察,该图存在负边权,但不存在带负权值的回路,问下列哪个算法可以求解最短路?
不过考察可能性不大,模拟算法的简单步骤更为有可能。
- 最小生成树
性质
-
最小生成树不唯一
-
最小生成树树形不唯一
-
各边权值互不相等时,唯一
扫描二维码关注公众号,回复: 14963862 查看本文章 -
权值之和唯一
-
对于生成树来说,加一条边,会形成一条回路,减一条边,会变成非调通图
-
最小生成树的边数为顶点数-1
-
prim算法-point-加点-对边稠密
-
kruskal-加边-对边稀疏
- 有向无环图的描述表达式(注意化简即可)
- 拓扑排序(可能考算法分析题?)
- 关键路径(可能考算法分析题?)
选择8-B树(B-树)
2022年考察了B树的删除
对于B树的插入、失败节点n+1、
- 每个结点至多m颗子树,m-1个关键字
- 保证绝对平衡->根结点在非叶情况下至少有两个子树
- 叶子结点(失败结点,实际不存在),终端结点(叶子结点上一层结点)
- 最小高度-让每个结点尽可能地满,利用分叉去计算(n为树关键字的总数)
( m − 1 )( 1 + m + m 2 + . . . + m h − 1 ) = n (m-1)(1+m+m^2+...+m^h-1)=n (m−1)(1+m+m2+...+mh−1)=n - 最大高度-利用h+1层有失败节点个数为n+1个去计算(n为树关键字的总数)
2 ∗ [ c e i l i n g ( m / 2 ) ] ( h − 1 ) = n + 1 2*[ceiling(m/2)]^(h-1)=n+1 2∗[ceiling(m/2)](h−1)=n+1
5.B树的高度通常不包括叶子结点
B树的插入
选择8-B+树
- m阶B+树定义
- 同样最多m棵子树,最少ceiling(m/2)棵子树
- 关键字个数范围
[ c e i l i n g ( m / 2 ) , m ] [ceiling(m/2),m] [ceiling(m/2),m]
- 叶结点
- 叶结点有指向记录的指针
- 叶结点水平链接,以便于遍历查找
选择8-B树与B+树的区别
选择8-B树与B+树的相关应用
【参考2017年真题】B+树是应文件系统需要产生的B树的变形,前者比后者更适合实际应用中的操作系统的文件索引和数据库索引,因为前者的磁盘读写代价低,查询效率更加稳定。
(其他,编译器中词法分析使用的是有穷自动机和语法树,网络中路由表快速查找主要依靠高速缓存、路由表压缩技术、快速查找算法)
选择9-查找
- 二叉排序树
- 可以问该序列是否符合二叉排序树
- 二叉查找判定树
- 感觉考察该知识点,不如考察平衡二叉树或者B+树新考点
这里【2017年选择题】考过让你判断哪个树型可能成为二叉查找判定树,较为新颖,围绕定义。
- 平衡二叉树
- 平衡二叉树的调整
- 平衡二叉树的建立
- Hash表的查找
- 线性探测法考频最高,掌握好平均查找成功的长度和平均查找失败的长度
注意:查找失败的情况,比较空白位置也算一次比较;还有分母的大小
6. 线性探测法会造成“集聚”现象
7. 平方探测法,处理冲突的较好方法,可以避免“集聚”现象
选择10、11-排序算法
- 考察排序算法的概念
- 不同排序算法的差别
- 重点:快速排序
- 让你判断下列序列是否符合第x趟排序
每一次找定基准元素,都会导致将序列分为两个表,并对两个表进行快速排序【2019年选择题】 - 或者是让你进行一趟快速排序的结果
- 希尔排序
- 近几年没见了,稍微准备下,即把相隔某个增量的记录组成一个子表,对子表进行直接插入排序
快速排序代码
void quicksort(int a[], int low, int high){
if (low < high){
int pos = partition(a, low, high);
quicksort(a, low, pos-1);
quicksort(a, pos+1, high);
}
}
//partition是一趟划分
int partition(int a[], int low, int high){
int pos = a[low];//将表中第一个元素设置位枢轴
while(low < high){
//从右边找到第一个比枢轴值小的
while(low < high && a[high] >= pos) --high;
a[low] = a[high];
while(low < high && a[low] >= pos) ++low;
a[high] = a[low];
}
a[low] = pos;
return low;
}
注:通过代码也可以看出来,一趟排序是包括一次partition和两个quicksort
内部排序算法的比较
比较次数 与序列初态 无关 的算法是:简单选择排序、基数排序
比较次数 与序列初态 有关 的算法是:快速排序、直接插入排序、冒泡排序、堆排序、希尔排序、二路归并排序
排序趟数 与序列初态 无关 的算法是:直接插入排序、折半插入排序、希尔排序、简单选择排序、归并排序、基数排序
排序趟数 与序列初态 有关 的算法是:冒泡排序、快速排序
总移动次数 与序列初态 无关 的算法是:二路归并排序、基数排序
时间复杂度 与序列初态 无关 的算法是:简单选择排序、堆排序、归并排序、基数排序
从稳定性来看,
稳定:插入排序、冒泡排序、归并排序、基数排序
不稳定:快速排序、简单选择、希尔排序、堆排序
- 若n较小,可以使用直接插入排序或者简单选择排序。直接插入需要记录的移动次数会比简单选择的多,记录本身信息量较大时,用简单选择排序比较好。
- 初始基本有序,直接插入或者冒泡排序
- n较大时,快速排序、堆排序、归并排序,快速排序速度快、堆排序辅助空间小于快排、但前两者不稳定,使用直接插入的归并排序算法是稳定的,可以考虑
- 关键字位数较少且可以分解时,基数排序
综合应用题41-算法题
反转链表1
题源1:反转链表1
比较简单,可以作为思想记忆,不太会这么直接考察
408可能考察链表的实现,
ListNode* reverseList(ListNode* head) {
if(head == NULL) return NULL;
//头插法
ListNode * p = head;//工作指针,指向链表的最后一个位置,由于leetcode没有头结点后面相当于把最后一个结点当作头结点使用
ListNode * q = head;
while(p->next != NULL){
p = p->next;
}
//开始头插
//工作指针
p->next = NULL;
ListNode *r;
while(q != p){
r = q->next;
q->next = p->next;
p->next = q;
q = r;
}
return p;
}
反转链表2
题源2,反转链表2
题解
中等难度+链表,实际上是比较合适考研出题的。
代码量也不大。
- curr:指向待反转区域的第一个节点 left;
- next:永远指向 curr 的下一个节点,循环过程中,curr 变化以后 next 会变化;
- pre:永远指向待反转区域的第一个节点 left 的前一个节点,在循环过程中不变。
代码
ListNode* reverseBetween(ListNode* head, int left, int right) {
//设置dummyNode
ListNode *dummyNode = new ListNode(-1);//设置哑结点,就是头结点
dummyNode->next = head;
//已pre作为头结点进行头插法,使得left到right区域内反转
ListNode * curr; //指向待反转区域的第一个结点
ListNode * cnext; //curr的下一个结点
ListNode * pre; //指向待反转区的前一个结点
pre = dummyNode;
for(int i = 0; i < left - 1; i++){
pre = pre->next;
}
curr = pre->next;
//拉直过后curr自己向后移动了,不需要再curr = curr->next
for(int i = 0; i < right - left; i++){
cnext = curr->next; //记录当前位置的下一个位置
curr->next = cnext->next;
cnext->next = pre->next;
pre->next = cnext;
}
return dummyNode->next;
}
2019年真题-链表逆置(头插法)
题解
可以将头插法逆置分解为以下这几个步骤
注:图示2号是要头插的第一个元素,头结点是1号
-
头结点断开
p->next = NULL;
-
当q不为空结点时,说明有元素进行头插法
(a)工作指针r指向要进行头插元素的后一个元素r=q->next;
(b)头结点的下一个结点指向要进行头插的结点,即为q结点p->next=q;
[p的值是不会在头插过程中发生改变的,头插二字也可从此理解]
©进行头插的结点断开q->next=NULL;
(d)头插下一个结点q=r;
代码
typedef struct LNode{
ElemType data;
struct Lnode *next;
} LNode, *LinkList;
void slove(LinkList * h){
LinkList *p, *q, *r, *s;//工作指针
p = q = h;
//寻找中间结点
while(q->next != NULL){
p = p->next;
q = q->next;
if (p->next != NULL) p = p->next;
}
q = p->next; //令q指向后半段首结点
p->next = NULL;
//将后半段链表逆置
while(q != NULL){
r = q->next;
q->next = p->next;
p->next = q;
q = r;
}
//逐一插入即可
s = h->next;
q = p->next;
p->next = NULL;
while(q != NULL){
r = q->next;
q->next = s->next;
s->next = q;
s = q->next;
q = r;
}
}
综合应用题-42
拓扑排序相关分析题
采用邻接表时间复杂度为O(|V|+|E|)采用邻接矩阵时间复杂度为O(|V|^2)
- 从AOV网中选择一个没有前驱的顶点并输出
- 从网中删除该顶点和所有以它为起点的有向边
- 重复1、2直至当前AOV网为空,或者是不存在无前驱的顶点为止。
后一种情况说明,有向图中存在环
- 可以考察拓扑排序的步骤
- 考察判断一个有向图是否有环
- 问什么情况下拓扑排序不唯一,一个顶点有多个直接后继的时候
- 对于一般的图来说,若其邻接矩阵是三角矩阵,则存在拓扑序列;但存在拓扑序列,其邻接矩阵不一定是三角矩阵
计算机组成原理
选择12-计算机系统性能指标
- cpi
- 时钟周期
选择13-补码
- 补码的表示范围
- 给你一个小数、整数,让你选择以下哪个16进制数是该数的补码表示
选择14-IEEE754浮点数的表示
选择15-
选择17-主存储器与cpu的连接
选择18-乘法电路的基本原理
选择19-指令系统
- 扩展编码方式
选择20-
选择21-I/O方式
个人认为以后的IO主要都是以选择题出现,较为简单且计算量不大,考察IO时间占时钟周期的比
IO流程与解答方法主要书写在该篇文章月光不染是非-IO流程分析与解答
2023应注重DMA方面的考察
综合应用题43-存储系统相关
关键词:cache-内存-外存、三级存储
综合应用题44-指令系统
关键词:MIPS、指令流水线、x86
个人觉得考MIPS的优先级会高于x86
操作系统
综合应用题45-PV-生产者消费者
- 写优先
- 读写公平法
- 读优先(饥饿)
当有以下信息时候考虑是不是读者写者问题
- 两组并发进程
- 共享一个文件
- 两个或以上读者访问不会产生副作用
- 某个写进程和其他进程(读进程或写进程)同时访问就可能出错
- 允许多个读者可以同时对文件执行读操作
- 只允许一个写者往文件中写信息
- 任一写者在完成写操作之前不允许其他读者或者写者工作
- 写者执行写操作前,应让已有读者和写者退出、
于是,存在这么两组互斥关系
- 读者和写者互斥
- 写者和写者互斥
//读者进程
reader(){
while(true){
p(WriteFirst);//如果在写则无法进行读
//由于有多个读进程,所以对count的修改需要互斥
p(mutex);
if(count == 0){
//阻止写进程写
p(WriteMutex);
}
count++;
v(mutex);
v(WriteFirst); //恢复对共享文件的访问
reading;
p(mutex);//读完修改count
count--;
if (count == 0){
v(WriteMutex);//读完写进程才可以有机会进入;有P就有V
}
v(mutex);
}
}
//写者进程
writer(){
while(true){
p(WriteFirst);//用于实现写优先
p(WriteMutex);//用于实现写者与其他进程都互斥
writing;
v(WriteMutex);
p(WriteFirst);
}
}
//信号量
semephore WriteFirst = 1; //写进程优先
semaphore WriteMutex = 1; //用于保证写者进程运行时,其他进程无法运行
semaphore mutex = 1; //实现对count的互斥访问
int count = 0;
例题:(王道冲刺课,教练与球员,更衣室)
教练=写者
球员=读者
更衣室=资源
writer(){
while(true){
p(WriteFirst);
p(WriteMutex);
教练使用更衣室;
v(WriteMutex);
v(WriteFirst);
}
}
reader(){
while(true){
p(WriteFirst);
p(mutex);
if (count == 0){
p(WriteMutex);
}
count++;
v(mutex);
v(WriteMutex);
球员使用更衣室;
p(mutex);
count--;
if (count == 0){
v(WriteMutex);
}
v(mutex);
}
}
//信号量
semephore WriteFirst = 1; //写进程优先
semaphore WriteMutex = 1; //用于保证写者进程运行时,其他进程无法运行
semaphore mutex = 1; //实现对count的互斥访问
int count = 0;
综合应用题46-内存管理
关键词:分页、内存和外存
计算机网络
综合应用题47-围绕网络拓扑进行分析
关键词:vlan、路由器、