一、递归时间/空间分析
1.时间复杂度的分析
设
F
a
c
t
(
n
)
Fact(n)
Fact(n)的执行时间是
T
(
n
)
T(n)
T(n)。
if(n==0) return 1; 的执行时间是
O
(
1
)
O(1)
O(1),
F
a
c
t
(
n
−
1
)
Fact(n-1)
Fact(n−1)的执行时间是
T
(
n
−
1
)
T(n-1)
T(n−1),
所以else return
n
∗
F
a
c
t
(
n
−
1
)
n*Fact(n-1)
n∗Fact(n−1); 的执行时间是
O
(
1
)
+
T
(
n
−
1
)
O(1)+T(n-1)
O(1)+T(n−1)。
推出: T ( n ) = n C + T ( 0 ) = n C + D T(n)=nC+T(0)=nC+D T(n)=nC+T(0)=nC+D, T ( n ) = O ( n ) T(n)=O(n) T(n)=O(n)
【小结论】:Fibonacci数列和Hanoi塔问题递归算法的时间复杂度均为O(2^n)。
2.空间复杂度分析
空间复杂度 S ( n ) = O ( f ( n ) ) S(n)=O(f(n)) S(n)=O(f(n)),其中, f ( n ) f(n) f(n)为“递归工作栈”中工作记录的个数与问题规模 n n n 的函数关系。
【小结论】:阶乘间题、Fibonacci数列问题、Hanoi塔问题的递归算法的空间复杂度均为O(n)。
二、KMP算法求next数组和nextval
1.next[i]
前2位一般为:0,1
i位看前i-1位最大公共部分末尾坐标+1
2.nexval[i]
前1位一般为:0
t[next[i]]位置元素是不是和t[i]一样,一样的话将t[next[i]]的nextval写在当前nextval[i];不一样的话就将当前的next[i]里面数写在nextval[i]
三、数组存贮(选择&简答)
1.对称矩阵
2.三角矩阵
(1)上三角
(2)下三角
四、广义表—求表头/表尾/长度/深度(选择&简答)
1.取表头Head(A)
就取A的第一个元素
2.取表尾Tail(A)
就是扣掉第一个元素,留下的所有的(包含A最外面的大括号)
3.长度
就是元素的个数
4.深度
就是数左or右括号的个数
五、前/中/后/层序遍历二叉树+先后根遍历森林
1.前序/前缀表达式/波兰式
树:根左右
森林:根左到右
RADEBCFGHK
2.中序/中缀表示
树:左根右
把一个树拍扁了就是中序~
3.后序/后缀表达式/逆波兰式
树:左右根
森林:左到右根
DEABGHKFCR
六、前/后/层次+中序确定二叉树
1.前序+中序
2.后序+中序
3.层次+中序
4.拓展
①已知前序有多少种二叉树?
入栈出栈个数:
1
/
(
n
+
1
)
C
2
n
n
1/(n+1) C_2n^n
1/(n+1)C2nn种(n为结点个数)
七、前中后序线索二叉树的构建
1.线索二叉树构建方法
Step1:写出对应的先/中/后序遍历
Step2:如果结点左孩子为空,结点左链连接序列左边的元素;如果结点右孩子为空,结点右链连接序列右边的元素;
八、树/森林与二叉树的转换
变森林/树:删右腿
变二叉树:连右兄弟
1.树→二叉树
2. 二叉树→树
3.森林转→二叉树
4.二叉树→森林
九、哈夫曼树——构造/WPL/HT初始和终结状态
十、邻接矩阵/邻接表/逆邻接表/十字链表—构建、出入度
1.邻接矩阵
①无向图
出入度:第i行or第j列非零元素的个数是顶点i的度
②有向图
出入度:第i行非零元素的个数是顶点i的出度;第j列非零元素的个数正好是顶点i的入度
2.邻接表
①无向图
info是权重
出入度:遍历“一行”
②有向图
出度:遍历“一行”
入度:遍历v的每行
3.逆邻接表
与邻接表箭头相反
4.十字链表
十字链表的画法
Step1.编号
Step2.组队:编号结点出去的箭头
Step3.连线:前同横线,后同竖线
十一、生成树—深度优先/广度优先
十二、最小生成树—Prim/Kruskal
1.普里姆 (Prim) 算法
从某点出发,找最短的边加入集合,再以集合为整体继续加入边。过程中不能出现回路!
2.克鲁斯卡尔 (Kruskal) 算法
直接找最小的边,过程中不能出现回路!
十三、最短路径—Dijkstra/Floyd
1.从某个源点到其余各顶点的最短路径迪杰斯特拉(Dijkstra)算法
从某点出发,找最短的边加入集合,再以集合为整体继续加入边。
与Prim不同的是,Prim只用看集合相连的最短,Dijkstra还要算一算。
2.每一对顶点之间的最短路径弗洛伊德(Floyd)算法
不断基于对角线上元素画“十字”计算的过程
Step1.从第一个对角线元素开始不断画十字
Step2.十字和它∞部分对应的行列值不变
Step3.更新值(值比原来元素小才更新)与路径,取下一个对角线元素继续重复
十四、拓扑排序/逆拓扑排序
1.AOV-网
这种用顶点表示活动,用弧表示活动间的优先关系的有向图称为顶点表示活动的网。AOV-网是无环的有向图(DAG)
2. 拓扑排序
就是将AOV-网中所有顶点排成一个线性序列,该序列满足:若在AOV-网中由顶点Vi到顶点Vj有一条路径,则在该线性序列中的顶点Vi必定在顶点Vj之前。
拓扑排序做法
Step1.在有向图中选一个无前驱的顶点且输出它。
Step2.从图中删除该顶点和所有以它为尾的弧。
Step3.重复1.和2.直至不存在无前驱的顶点。
若此时输出的顶点数小于有向图中的顶点数,则说明有向图中存在环,否则输出的顶点序列即为一个拓扑序列。
逆拓扑排序做法
在有向图中选一个无后继的顶点且输出它。(其余和拓扑排序一样)
十五、AOE-网—事件&活动最早/最迟/时间余量/关键活动/关键路径
1. AOE-网
AOE-网是一个带权的有向无环图,其中,顶点表示事件,弧表示活动,权表示活动持续的时间
ve(1):事件v_1的最早发生时间
vl(1):事件v_1的最迟发生时间
早顺迟逆;早+迟-;早大迟小
说明:最早时间从源点顺着往汇点走
最迟时间从汇点逆着往源点走
最早时间顺着走的时候遇到两条道路选相加最大的
最迟时间逆着走的时候遇到两条道路选相减最小的
e(1):活动a_1的最早开始时间
l(1): 活动a_1的最迟开始时间
早=弧尾早;迟=弧头迟-权值
说明:最早时间是<x,y>弧尾事件的最早开始时间
最迟时间是<x,y>弧头事件的最迟开始时间-<x,y>的权值
2.关键路径
关键路径上的活动没有时间余量,即l(1)-e(1)=0
关键路径:路径长度最长的路径,完成工程至少需要的时间
关键路径上的活动是影响工程的关键活动
十六、顺序查找—顺序/折半/分块
1.顺序
(1)普通顺序查找
ASL成功=
(
(
1
+
2
+
3
+
⋯
+
n
)
)
/
n
=
(
1
+
n
)
/
2
((1+2+3+⋯+n))/n=(1+n)/2
((1+2+3+⋯+n))/n=(1+n)/2
ASL不成功=
n
+
1
n+1
n+1
时间复杂度:
O
(
n
)
O(n)
O(n)
(2)有序表的顺序查找
ASL不成功=
(
(
1
+
2
+
3
+
⋯
+
n
+
n
)
)
/
(
n
+
1
)
=
n
/
2
+
n
/
(
n
+
1
)
((1+2+3+⋯+n+n))/(n+1)=n/2+n/(n+1)
((1+2+3+⋯+n+n))/(n+1)=n/2+n/(n+1)
2.折半
要求:线性表必须采用顺序存储结构,而且表中元素按关键字有序排列
ASL成功=
时间复杂度为:$O(log_2 n)$
3.分块
ASL成功= Lb+Lw
Lb为查找索引表确定所在块的平均查找长度,Lw为在块中查找元素的平均查找长度
十七、树表的查找—BTS/AVL/B/B+
1.二叉排序树(BTS)
(1)定义
①若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
②若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
③它的左、右子树也分别为二叉排序树。
(2)性质
中序遍历一棵二叉树时可以得到一个结点值递增的有序序列
(3)插入
插入一定是叶子结点
(4)构造
(5)删除
①删叶子,直接删
②删无左孩子/无右孩子,孩子替换要删的结点
③删有左右孩子,找中序遍历的直接前驱/后继,替换要删的结点,删去这个前驱/后继,变为①②
【说明】:反正保证二叉排序树中序遍历有序就行
(6)ASL O()
ASLa成功=(11+22+34+43)/10=2.9
ASLa不成功=(35+46)/11=3.545
若二叉排序树左右子树高度只差的绝对值不超过1(平衡二叉树),它的平均查找长度为O(log2n)。
若二叉排序树是一个只有右(左)孩子的单支树(类似于有序的单链表),则其平均查找长度为O(n)。
2.平衡二叉树AVL
(1)定义
结点左子树与右子树的高度差为该结点的平衡因子,则平衡二叉树结点的平衡因子的值只可能是-1、0或1。
(2)插入
从接入的点往上找“最小不平衡子树”的根,找根在这条路径上最近的3个结点调整,调整完剩余结点按定义去放
①LR:
②LL:
③RR:
④RL:
(3)O()
时间复杂度O(log2n)
3.B-树
(1)定义
一棵m阶的B树,或为空树,是所有结点的平衡因子=0的m路平衡查找树
①树中每个结点至多有m棵子树,最多有m-1个关键字
②若根结点不是叶子结点,则至少有两棵子树;
③除根之外的所有非终端结点至少有 个子树,至少含有 个关键字;
④所有的叶子结点都出现在同一层次上,并且不带信息,通常称为失败结点(失败结点并不存在,指向这些结点的指针为空。引入失败结点是为了便于分析B-树的查找性能);
4.B+树
B+树和B-树的差异
(1)有n棵子树的结点中含有n个关键字;
(2)所有的叶子结点中包含了全部关键字的信息,以及指向含这些关键字记录的指针,且叶 子结点本身依关键字的大小自小而大顺序链接;
(3)所有的非终端结点可以看成是索引部分,结点中仅含有其子树(根结点)中的最大(或最小)关键字。
十八、散列表—构造/冲突/查找
①散列函数和散列地址:在记录的存储位置p和其关键字key之间建立一个确定的对应关系H, 使p=H(key), 称这个对应关系H为散列函数,p为散列地址。
1.构造方法
除留余数法:假设散列表表长为m, 选择一个不大于m的数p, 用p去除关键字,除后所得余数为散列地址,即H(key) = key%p。一般情况下,可以选p为小于表长的最大质数。
2.处理冲突的方法
(1)开放地址法
H
i
=
(
H
(
k
e
y
)
+
d
i
)
H_i= (H(key) +d_i)%m
Hi=(H(key)+di)
①线性探测法:d_i = l, 2, 3, …, m-1
②二次探测法:
(2)链地址法
3. 查找
查找过程中需和给定值进行比较的关键字的个数取决于三个因素:散列函数、处理冲突 的方法和散列表的装填因子a
列表的装填因子a定义为 a=表中填入的记录数/散列表的长度
十九、插入排序—直接插入/折半插入/希尔
1.直接插入排序
后面没有排好的一个一个往排好的里面丢,比较时候根排好的最后一个元素比
2.折半插入排序
后面没有排好的一个一个往排好的里面丢,比较时候根排好的中间元素比
但对于数据量不很大的排序表,折半插入排序往往能表现出很好的性能。折半插入排序仅减少了比较元素的次数约O(nlogn),元素的移动次数并未改变,它依赖于待排序表的初始状态。
3.希尔排序
Step1.定义增量序列Dk : Dm>Dm-1>…>D1=1(互质)
Step2.对每个Dk进行Dk间隔插入排序
二十、交换排序—冒泡/快速
1.冒泡排序
从前两两对比,大的往后放
2.快速排序
二十一、选择排序—简单选择/堆排
1. 简单选择排序
遍历找小的放前面
2. 堆排序
(1)建堆(例题1)
(2)重建堆(堆排序过程)(例题1)
根与最后一个元素换位置,输出最后一个元素(也就是根),然后建堆
二十二、归并排序
两路归并就是两个两个排序,排好之后,再四个四个排,以此类推
二十三、基数排序
二十四、排序算法时间/空间/稳定性记忆
B站: BV1NL4y1t7Do
稳定性:插帽龟(插入冒泡归并)🐢,统计鸡(桶排计数基数)🐓
时间复杂度:插帽龟选择帽子插(选择冒泡插入)的时候,恩姓长老就方了(n^2),大喊“快归堆”(快速归并堆排)(logn)