第一部分 基础知识·
循环不变式·
初始化:循环的第一次迭代之前为真
保持:循环的某次迭代之前为真,则在下次迭代之前也为真
终止:循环终止时,不变式提供有用性质,有助于证明算法成立
第四章 分治策略·
归并排序·
最大子数组问题·
将数组切成左右两部分,则最大子数组要么出现在[l,mid]中,要么跨越了mid,要么就在[mid+1,r]中
矩阵乘法的Strassen算法·
https://zhuanlan.zhihu.com/p/78657463
思想:矩阵乘法算法复杂度高,用矩阵加减法代替部分的矩阵乘法运算
从$O(n3)$降到了$O(n{lg7})$,但由于涉及多次浮点数加减乘除,算法稳定性精确度较低。对于n>300时才适用
求解递归式·
递归树,归纳法,主方法
主方法·
$T(n)=aT(n/b)+f(n)$ $a\ge1,b>1,\epsilon>0$
-
$f(n)=O(n{log_b{a-\epsilon}})\rightarrow T(n)=\Theta(n{log_ba})$
-
$f(n)=\Theta(n{log_b{a}})\rightarrow T(n)=\Theta(n{log_ba}lgn)$
-
$f(n)=\Omega(n{log_b{a+\epsilon}})且\exists c\lt1,s.t.\forall n, af(n/b)\leq cf(n)(正则条件)\rightarrow T(n)=\Theta(f(n))$
主定理理解:情况1和3的小于和大于必须是多项式意义的大小关系,即如果没有相差$n^\epsilon$因子,则进入了1和2或者2和3的缝隙
第五章 概率分析与随机算法·
雇用问题·
随机化输入之后复杂度为$O(\ln n)$
随机化序列方法·
PERMUTE-BY-SORTING方法随机化优先级,根据优先级对数组排列
1 | permutes=[] |
RANDOMIZE-IN-PLACE方法
1 | for i in range(n): |
第二部分 排序与顺序统计量·
第6章 堆排序·
与插入排序一样是原址排序,复杂度与归并排序相当。
堆可以看成一个完全二叉树
最大堆—进行堆排序
最小堆—构造优先队列
MAX-HEAPIFY(A, i):维护i节点为根的子树的最大堆性质
1 | n=len(A) |
BUILD-MAX-HEAP(A):遍历[length/2,1]调用MAX-HEAPIFY
HEAPSORT(A):堆排序
1 | BUILD-MAX-HEAP(A) |
优先队列·
共享计算机系统的作业调度
MAXIMUM(S):return S[0]
EXTRACT-MAX(x):删去最大的并维护最大堆
1 | max=S[0] |
INCREASE-KEY(S,i,k):增加i位置的元素值到k
1 | if k<S[i]: |
INSERT(S,x):新增一个元素
1 | import sys |
第7章 快速排序·
QUICKSORT·
1 | a=[3,4,1,5,2] |
只要是常数划分,时间复杂度都是$O(n\lg n)$
随机化划分则算法复杂度为$O(n\lg n)$
第8章 线性时间排序·
决策树模型·
每一层表示不同层级条件分支,叶子节点表示排序后的标号序列
决策树的叶节点数量为l
则对于一个长度为n的排列
$n!\leq l \lt 2^h$
$h>\lg (n!)=\Omega(n\lg n)$
因此任何排序算法的下界为$O(n\lg n)$
不采用比较方式的排序需要更多空间,但时间复杂度突破了这个瓶颈,以下几个都为$\Theta(n)$
计数排序·
稳定排序:相同数值的两个数排序前后相对次序不变
空间消耗大
1 | a=[4,2,3,1,6,8,7,0,9,1,12] |
基数排序·
早期卡片编程用到
n次循环(i from 1 to n),每次序列对第i位数按照从小到大排序,最后的顺序就是从小到大
要求对一位数的排序为稳定排序
桶排序·
将[0,1]划分为[0,1/n],[1/n,2/n]…[(n-1)/n,1]区间
每个数都属于一个小区间中,对每个区间内的数建立链表,使用插入排序。
1 | a=[4,2,3,1,6,8,7,0,9,1,12] |
第9章 中位数与顺序统计量·
第i个顺序统计量:一个序列中第i小的元素
选择问题·
输入:一个集合A和一个数i
输出:第i个顺序统计量
利用快速排序中的随机划分函数
1 | def randomselect(a,l,r,i): |
select算法·
https://blog.csdn.net/luoshixian099/article/details/45286303
第三部分 数据结构·
第10章 基本数据结构·
栈:后进先出·
队列:先进先出·
链表·
1 | class node: |
哨兵用一个哨兵对象nil表示NULL
哨兵可以降低常数因子,但占用额外空间比较浪费,一般不用
1 | L.nil.prev=L.tail |
有根树的表示·
1 | class treenode: |
第11章 散列表·
直接寻址表·
即数组,根据关键字k直接索引元素
散列表·
根据函数h(k)的值索引元素
冲突解决办法:链接法 开放寻址法
链接法·
假设任何一个给定元素等可能散列到m个槽中任何一个,与其他元素被散列到哪无关,这个假设为简单均匀散列
每个槽对应一个链表,冲突则放在链表中
散列函数·
多数散列函数都假定关键字全域为自然数集N,如果不是自然数集则一般要通过某种方式转换为自然数,比如字符串和Ascii码
除法散列法·
$h(k)=k\ mod\ m$
m一般取不接近2的整数幂的素数
乘法散列法·
$h(k)=\lfloor m((kA)\ mod\ 1)\rfloor$
其中 $((kA) mod 1)$ 为取 $kA$ 的小数部分 $0\leq A \leq 1$
由于移位乘法比较简单,A一般取形如$s/2^w$的一个小数,m一般取2的整数幂
Knuth认为$A=(\sqrt 5 -1)/2=0.6180339887…$比较合适
全域散列法·
随机选择散列函数,使之独立于关键字
开放寻址法·
$h:U\times{0,1…m-1}\rightarrow {0,1…m-1}$
对每一个关键字k,使用开放寻址法的探查序列 $<h(k,0),h(k,1),…,h(k,m-1)>$ 选择空的槽位
探查方式
- 线性探查
- 二次探查
- 双重散列
完全散列·
二级散列表,每一级都采用全域散列
第12章 二叉搜索树·
在一棵高度h的二叉树上,动态集合上的操作SEARCH/MINIMUM/MAXIMUM/SUCCESSOR/PREDECESSOR/DELETE/INSERT均可以在O(h)内完成
第13章 红黑树·
平衡搜索树
第14章 数据结构的扩张·
扩张数据结构的步骤·
- 选择一种基础数据结构
- 确定基础数据结构中要维护的附加信息
- 检验基础数据结构上的基本修改操作能否维护附加信息
- 设计一些新操作
顺序统计树——在红黑树基础上对每个结点增加一个表示子树大小的size变量
区间树——红黑树基础上,关键字采用区间信息和端点最大值