一、数据结构
1、红黑树、序统计树、区间树
1.1 红黑树的性质
- 每个节点是红色或黑色的
- 根节点是黑色的
- 叶节点是黑色的
- 红色节点的两个孩子节点都是黑色的
- 从一个节点到后代任意叶节点的简单路径上,黑色节点数相同,即黑高相同
1.2 红黑树的应用 - 顺序统计树、区间树的定义、构造
-
顺序统计树
顺序统计树是一种支持快速顺序统计操作的一种数据结构
其可以在 O ( l g ( n ) ) O(lg(n)) O(lg(n)) 复杂度下去定位一个节点的秩,或找到秩为 x x x 的节点
它在红黑树的基础上,在每个节点中添加了一个附加信息 s i z e size size,该属性标识以该节点为根的树的节点数
-
区间树
区间树是一种对动态集合进行维护的红黑树
1.3 数据结构扩张步骤
- 选择一种基础数据结构
- 确定基础数据结构中要维护的附加信息
- 检查基础数据结构上的基本操作能否维护附加信息
- 设计一些新的操作
1.4 一些题目
-
证明:一颗有n个内部节点的红黑树的高度至多为 2 l g ( n + 1 ) 2lg(n+1) 2lg(n+1)
假设一颗红黑树的高度为 h h h,根据性质4,从根到叶节点的任何一条简单路径上都至少有一半的节点为黑色,因此,根的黑高至少为 h / 2 h/2 h/2,于是有
n ≥ 2 h / 2 − 1 n \geq 2^{h/2}-1 n≥2h/2−1
从而可以得到 h ≤ 2 l g ( n + 1 ) h \leq 2lg(n+1) h≤2lg(n+1) -
在一棵黑高为 k k k 的红黑树中,内部节点最多可能有多少个?最少可能有多少个?
最多时,从根节点到任意叶节点的简单路径上,有 k k k 个黑节点,有 k k k 个红节点,此时节点数为 2 2 k − 1 2^{2k}-1 22k−1
最少时,从根节点到任意叶节点的简单路径上,只有 k k k 个黑节点,此时节点数为 2 k − 1 2^k-1 2k−1
-
红黑树新插入节点时,为何不着色为黑色?着色为黑色,就不会破坏性质4啊
着色为黑色的话,就会破坏性质5,处理起来更加麻烦
2、二项堆
2.1 二项树的定义、性质
对于一颗二项树 B k B_k Bk,它具有以下性质:
- 有 2 k 2^k 2k 个节点
- 树高为 k k k
- 在 i i i 层上,恰好有 C k i C_k^i Cki 个节点, i ∈ [ 0 , k ] i \in [0,\,k] i∈[0,k]
- 根节点的度为 k k k,大于其他任意节点;且其 k k k 个孩子节点的度从左到右依次为 k − 1 , k − 2 , . . . , 0 k-1,\,k-2,...,0 k−1,k−2,...,0;同样的,以其孩子节点为根的树也是一颗二项树,不断递归定义下去
- B k B_k Bk 可由两棵 B k − 1 B_{k-1} Bk−1 合并而来
2.2 二项堆的定义
对于一个二项堆 H H H,其遵循以下性质:
- H H H 中的每一棵二项堆均为小顶堆
- 对任意一种度数 k k k,其对应的二项树 B k B_k Bk 在 H H H 中最多只出现一次
2.3 根表的性质
在二项堆 H H H 中,维护了一个叫根表的东西,且每个节点的 s i b l i n g sibling sibling 指针指向其兄弟节点,根表是存储二项堆中的所有二项树的根的链表。且,在根表中,每个根的 d e g r e e degree degree 是严格递增的
2.4 二项堆的操作、时间
- 创建新堆: O ( 1 ) O(1) O(1)
- 查找最小节点: O ( l g ( n ) ) O(lg(n)) O(lg(n)),对于有n个节点的二项堆,其最多有 ⌊ l g ( n ) ⌋ + 1 \lfloor lg(n) \rfloor + 1 ⌊lg(n)⌋+1 个二项树
- 合并两个二项堆: O ( l g ( n ) ) O(lg(n)) O(lg(n)),遍历根表,相同度数合并
- 插入节点:创建只含有该节点的新堆,然后合并两个堆, O ( l g ( n ) ) O(lg(n)) O(lg(n))
- 删除最小节点: O ( l g ( n ) ) O(lg(n)) O(lg(n)),找到最小根,将该节点的孩子节点都放到新堆中,合并两个堆
- 减小一个节点的值: O ( l g ( n ) ) O(lg(n)) O(lg(n)),最大深度为 ⌊ l g ( n ) ⌋ \lfloor lg(n) \rfloor ⌊lg(n)⌋
- 删除一个节点: O ( l g ( n ) ) O(lg(n)) O(lg(n)),先将节点降为比最小值还要小的值,然后删除最小节点
3、斐波那契堆
3.1 斐波那契堆的定义
一个斐波那契堆是一系列具有最小堆序的有根树的集合。
3.2 根表的性质
在斐波那契堆中,所有的树根都用左右指针链成了一个环形双链表,其中 H . m i n H.min H.min 指向最小根节点, H . n H.n H.n 表示根节点数量。根链表中树的次序可以任意。
3.3 斐波那契堆的势函数
对于给定的斐波那契堆 H H H,用 t ( H ) t(H) t(H) 表示 H H H 中根链表中的树的数量,用 m ( H ) m(H) m(H) 来表示 H H H 中已标记的节点数目,定义势函数如下:
ϕ ( H ) = t ( H ) + 2 m ( H ) \phi(H) = t(H) + 2m(H) ϕ(H)=t(H)+2m(H)
3.4 斐波那契堆的操作、时间
创建一个空斐波那契堆: O ( 1 ) O(1) O(1)
插入一个节点:真实代价 O ( 1 ) O(1) O(1),摊还代价 O ( 1 ) O(1) O(1)
寻找最小节点:真实代价 O ( 1 ) O(1) O(1),摊还代价 O ( 1 ) O(1) O(1)
合并斐波那契堆:真实代价 O ( 1 ) O(1) O(1),摊还代价 O ( 1 ) O(1) O(1)
连接两个根表,从 H 1 . m i n H_1.min H1.min 和 H 2 . m i n H_2.min H2.min 中选出最小根节点作为 H . m i n H.min H.min,并更新 H . m i n = H 1 . m i n + H 2 . m i n H.min=H_1.min+H_2.min H.min=H1.min+H2.min
**疑问:**若仅是这样合并,根表中同一种度数的节点会有多个
抽取最小节点:摊还代价 O ( l g ( n ) ) O(lg(n)) O(lg(n))
首先找到最小节点,若有孩子节点,则将其孩子节点添加到根表中,最后移除最小节点 z z z,此时若 z z z 的右孩子为自己,说明根表中无其他节点了,所以根表置空,否则执行 H . m i n = z . r i g h t H.min=z.right H.min=z.right,并调用合并根链表操作。
合并根链表操作需要一个辅助空间 A [ 0.. D ( H . n ) A[0..D(H.n) A[0..D(H.n),其中 A [ i ] A[i] A[i]表示当前遇到过的度数 i i i 指向的节点,如果有两个节点相同,则合并之。
合并根链表时是从 H . m i n H.min H.min 开始遍历根链表的,所以开始之前 H . m i n H.min H.min 是否指向最小节点并不重要
关键字减值:实际代价 O ( c ) O(c) O(c),摊还代价 O ( 1 ) O(1) O(1),其中 c c c 是执行级联剪除函数的次数
假设要将节点 x x x 的值减小到 k k k,首先要保证新值 k k k 不大于旧值,接着,若新值没有违反最小堆序,那么可以直接结束,否则,需要将节点 x x x 剪除,并向上级联剪除,级联剪除过程如下:
CASCADING-CUT(H, x): z = x.parent if x.mark = false: x.mark = true else: CUT(x) CASCADING-CUT(H, z)
对于一个节点 x x x,若:
- 1、在某时刻 x x x 为根节点
- 2、 x x x 被链接到某节点后变成了孩子节点
- 3、 x x x 的两个孩子节点被剪除
那么,若条件1、2发生,并且 x x x 的一个孩子节点被剪除,则 x . m a r k = t r u e x.mark=true x.mark=true,若在 x . m a r k = t r u e x.mark=true x.mark=true时, x x x 又被剪掉了一个孩子节点,那么, x x x 就会被级联剪除掉。
也就是说,每一次剪除都会产生一个根节点
对该方法进行势能分析:
若剪除了节点 x x x,后又进行了 c − 1 c-1 c−1次的级联剪除,那么共会产生 c c c棵新树,标记数的变化为: c − 1 c-1 c−1次级联剪除会消除 c − 1 c-1 c−1个标记,但是最后一次尝试级联时因未标记节点,故会产生一个标记节点,故新的标记数为 m ( H ) − c + 2 m(H)-c+2 m(H)−c+2
势能变化如下:
t ( H ) + c + 2 ∗ ( m ( H ) − c + 2 ) − [ t ( H ) + 2 ∗ m ( H ) ] = 4 − c t(H) + c + 2 * (m(H)-c+2) - [t(H) + 2 * m(H)] = 4-c t(H)+c+2∗(m(H)−c+2)−[t(H)+2∗m(H)]=4−c
那么根据势能法的摊还分析,最终的摊还代价为:
O ( c ) + 4 − c = O ( 1 ) O(c) + 4 - c = O(1) O(c)+4−c=O(1)删除一个节点: O ( l g ( n ) ) O(lg(n)) O(lg(n))
先减值减到最小,再进行抽取最小值节点操作
斐波那契堆的最大度数界为 O ( l g ( n ) ) O(lg(n)) O(lg(n))
3.5 一些题目
-
若只支持合并堆操作,那么含有n个节点的斐波那契堆中的最大度数为 ⌊ l g ( n ) ⌋ \lfloor lg(n) \rfloor ⌊lg(n)⌋
- 若 n = 2 k n = 2^k n=2k,则该堆中只有一颗二项树,此时该根节点有最大度数为 D ( n ) = k = ⌊ l g ( n ) ⌋ D(n)=k=\lfloor lg(n) \rfloor D(n)=k=⌊lg(n)⌋
- 若 n = 2 k + i n=2^k+i n=2k+i,此时斐波那契堆中出现的节点数最多的二项树有 2 k 2^k 2k个节点,该树根节点度数为 D ( 2 k ) = k = ⌊ l g ( n ) ⌋ D(2^k)=k=\lfloor lg(n) \rfloor D(2k)=k=⌊lg(n)⌋
综上所述,含有n个节点的斐波那契堆中的最大度数为 ⌊ l g ( n ) ⌋ \lfloor lg(n) \rfloor ⌊lg(n)⌋
-
使用聚合分析来证明 FIB-HEAP-DECREASE-KEY 的 O ( 1 ) O(1) O(1) 摊还时间是每一个操作的平均代价
假设第 i i i 次调用减值函数会调用 c i c_i ci 次级联切断函数,故 n n n 次调用一共可能调用 ∑ i = 0 n − 1 c i \sum_{i=0}^{n-1}c_i ∑i=0n−1ci 次级联切断。
但是,每一次CUT,都会产生一个根节点,而根节点无法再进行级联切断,故最多只能执行 n n n 次切断,总代价为 O ( n ) O(n) O(n)
因此,n次调用的平摊代价为 O ( n ) / n = O ( 1 ) O(n)/n=O(1) O(n)/n=O(1)
二、算法设计方法
1、分治法
1.1 基本步骤
- **分解:**将问题划分为一些子问题,子问题的形式与原问题一样,只是规模更小
- **解决:**递归地求解出子问题。如果子问题的规模足够小,则停止递归,直接求解
- **合并:**将子问题的解组合成原问题的解
1.2 适用条件
原问题可被分解为规模更小的相同问题
1.3 相关算法
- 归并排序
- 最大子数组问题
- 矩阵乘法的Strassen算法
2、动态规划
2.1 基本步骤
- 描述最优解的结构特征
- 递归地定义一个最优解的值
- 自底向上计算一个最优解的值——计算最优解
- 从已知的计算信息中构造一个最优解——构造最优解
2.2 基本要素
- 最优子结构
- 重叠子问题
2.3 相关算法
- 矩阵链乘
- 钢条切割
- 最长公共子序列(LCS)
- 最优二叉搜索树
2.4 如何证明最优子结构性质
利用
cut-and-paste
技术证明:作为构成原问题最优解的组成部分,每个子问题的解就是它本身的最优解,证明这一点是利用反证法:假定子问题的解不是其自身的最优解,那么我们可以从原问题的解中”剪切“掉这些非最优解,将最优解”粘贴“进去,进而得到原问题的一个更优解,然而这与最初的解释原问题的最优解的前提假设矛盾。
3 、贪心法
3.1 基本思想
- 将最优化问题转化为这样的形式:对其做出一次选择后,只剩下一个子问题需要求解
- 证明做出贪心选择后,原问题总是存在最优解,即贪心选择总是安全的
- 证明做出贪心选择后,剩余的子问题满足性质:其最优解与贪心选择组合即可得原问题的最优解,这样就得到了最优子结构
3.2 基本要素
- 最优子结构性质
- 贪心选择性质
3.3 相关算法
- 活动选择问题
- 赫夫曼编码
3.4 理论基础 - 胚的定义及相关概念
矩阵胚又称拟阵,是满足下述条件的序偶 M = ( S , Γ ) M=(S,\; \Gamma) M=(S,Γ):
- S S S 是一个有限集
- Γ \Gamma Γ 是 S S S 子集的一个非空族,并且对于任意 B ∈ Γ B \in \Gamma B∈Γ,若 A ⊆ B A \subseteq B A⊆B,有 A ∈ Γ A \in \Gamma A∈Γ。此性质称为遗传性
- 若 A ∈ Γ , B ∈ Γ A \in \Gamma,\; B \in \Gamma A∈Γ,B∈Γ,且 ∣ A ∣ < ∣ B ∣ |A| < |B| ∣A∣<∣B∣,则对于 x ∈ B − A x \in B-A x∈B−A,有 A ∪ { x } ∈ Γ A \cup \{x\} \in \Gamma A∪{x}∈Γ。此性质称为交换性
3.5 三种方法的相同及不同点
3.6 贪心选择性质的证明
正常的贪心选择为:选择一个元素,选择的元素为要得到的最优解
非正常的贪心选择为:选择一个元素,剩下的元素为要得到的最优解
三、算法分析
1、渐进符号
1.1 定义
Θ \Theta Θ 记号(渐近紧确界)
Θ ( g ( n ) ) = { f ( n ) ; 存 在 正 常 量 c 1 , c 2 和 n 0 , 使 得 对 所 有 的 n > n 0 , 有 0 ≤ c 1 g ( n ) ≤ f ( n ) ≤ c 2 g ( n ) } \Theta(g(n))=\{f(n); 存在正常量c_1,c_2和n_0,使得对所有的n>n_0,有0\leq c_1g(n) \leq f(n) \leq c_2g(n) \} Θ(g(n))={f(n);存在正常量c1,c2和n0,使得对所有的n>n0,有0≤c1g(n)≤f(n)≤c2g(n)}O O O 记号(渐近上界)
O ( g ( n ) ) = { f ( n ) ; 存 在 正 常 量 c 和 n 0 , 使 得 对 所 有 的 n > n 0 , 有 0 ≤ f ( n ) ≤ c g ( n ) } O(g(n))=\{f(n); 存在正常量c和n_0,使得对所有的n>n_0,有0\leq f(n)\leq cg(n) \} O(g(n))={f(n);存在正常量c和n0,使得对所有的n>n0,有0≤f(n)≤cg(n)}Ω \Omega Ω 记号(渐进下界)
Ω ( g ( n ) ) = { f ( n ) : 存 在 正 常 量 c 和 n 0 , 使 得 对 所 有 的 n > n 0 , 有 0 ≤ c g ( n ) ≤ f ( n ) } \Omega(g(n)) = \{f(n):存在正常量c和n_0, 使得对所有的n>n_0,有0\leq cg(n) \leq f(n) \} Ω(g(n))={f(n):存在正常量c和n0,使得对所有的n>n0,有0≤cg(n)≤f(n)}
1.2 三个符号间的关系
若 f ( n ) = Ω ( g ( n ) ) f(n)=\Omega(g(n)) f(n)=Ω(g(n)) 且 f ( n ) = O ( g ( n ) ) f(n) = O(g(n)) f(n)=O(g(n)),则有 f ( n ) = Θ ( g ( n ) ) f(n)=\Theta(g(n)) f(n)=Θ(g(n))
1.3 一些已知量间的渐进关系
1.4 题目
-
假设 f ( n ) f(n) f(n) 与 g ( n ) g(n) g(n) 都是渐近非负函数,使用 Θ \Theta Θ 记号的基本定义来证明 m a x ( f ( n ) , g ( n ) ) = Θ ( f ( n ) + g ( n ) ) max(f(n), g(n))=\Theta(f(n)+g(n)) max(f(n),g(n))=Θ(f(n)+g(n))
因为 f ( n ) f(n) f(n) 与 g ( n ) g(n) g(n) 均为渐近非负函数,因此有: f ( n ) ≥ 0 f(n)\geq 0 f(n)≥0 且 g ( n ) ≥ 0 g(n) \geq 0 g(n)≥0
那么有: 0 ≤ 1 2 ( f ( n ) + g ( n ) ) ≤ m a x ( f ( n ) , g ( n ) ) ≤ f ( n ) + g ( n ) 0 \leq \frac12(f(n) + g(n)) \leq max(f(n), g(n)) \leq f(n) + g(n) 0≤21(f(n)+g(n))≤max(f(n),g(n))≤f(n)+g(n)
即:存在 c 1 = 1 2 , c 2 = 1 , n 0 = 0 c_1=\frac12,\;c_2=1,\;n_0=0 c1=21,c2=1,n0=0 使得当 n ≥ n 0 n\geq n_0 n≥n0 时,有:
0 ≤ c 1 ( f ( n ) + g ( n ) ) ≤ m a x ( f ( n ) + g ( n ) ) ≤ c 2 ( f ( n ) + g ( n ) ) 0\leq c_1(f(n)+g(n)) \leq max(f(n)+g(n)) \leq c_2(f(n)+g(n)) 0≤c1(f(n)+g(n))≤max(f(n)+g(n))≤c2(f(n)+g(n))
即: m a x ( f ( n ) , g ( n ) ) = Θ ( f ( n ) + g ( n ) ) max(f(n),\;g(n))=\Theta(f(n)+g(n)) max(f(n),g(n))=Θ(f(n)+g(n)) -
证明:对任意常量 a a a 和 b b b,其中 b > 0 b > 0 b>0,有: ( n + a ) b = Θ ( n b ) (n+a)^b=\Theta(n^b) (n+a)b=Θ(nb)
- 当 a ≥ 0 a\geq0 a≥0, n > ∣ a ∣ n>|a| n>∣a∣ 时,有: 0 ≤ n b ≤ ( n + a ) b ≤ ( 2 n ) b = 2 b n b 0\leq n^b\leq (n+a)^b \leq (2n)^b=2^bn^b 0≤nb≤(n+a)b≤(2n)b=2bnb
- 当 a < 0 a<0 a<0, n ≥ ∣ 2 a ∣ n\geq |2a| n≥∣2a∣ 时,有: 0 ≤ 2 − b n b = ( 1 2 n ) b ≤ ( n + a ) b ≤ n b 0\leq 2^{-b}n^b=(\frac12n)^b \leq (n+a)^b \leq n^b 0≤2−bnb=(21n)b≤(n+a)b≤nb
综上所述,存在 c 1 = 2 − b , c 2 = 2 b , n ≥ ∣ a ∣ c_1=2^{-b},\;c_2=2^b,\;n\geq|a| c1=2−b,c2=2b,n≥∣a∣,使得下式成立:
0 ≤ 2 − b n b < n b ≤ ( n + a ) b ≤ n b ≤ 2 b n b 0\leq 2^{-b}n^b < n^b \leq (n+a)^b \leq n^b \leq 2^bn^b 0≤2−bnb<nb≤(n+a)b≤nb≤2bnb
即: ( n + a ) b = Θ ( n b ) (n+a)^b=\Theta(n^b) (n+a)b=Θ(nb)
2、传统分析方法
2.1 基本思想
通过计算每条语句的执行次数,后累加得到 T ( n ) T(n) T(n)
2.2 最好最坏情况下的时间复杂度分析
举例:插入排序的时间复杂度分析
3、递归算法的分析方法
3.1 T(n)的一般式
3.2 替换法(代入法)
-
求解步骤
- 猜测解的形式
- 用数学归纳法求出解中的常数,并证明解是正确的
-
注意
要做出好的猜测要靠经验,那么这里有一个微妙的细节:
有时你可能正确猜出了递归式解的渐近界,但莫名其妙的在归纳证明时失败了。问题常常出在归纳假设不够强,无法证出准确的界。当遇到这种障碍时,如果修改猜测,将它减去一个低阶的项,数学证明常常能顺利证明。后面会有题目例证。
3.3 递归树方法
通常可以使用递归树方法来猜测解,再用代入法来证明猜测的正确性
3.4 Master方法
-
针对的问题形式
T ( n ) = a T ( n / b ) + f ( n ) T(n)=aT(n/b)+f(n) T(n)=aT(n/b)+f(n)
-
主定理
令 a ≥ 1 a\geq 1 a≥1 和 b > 1 b > 1 b>1 是常数, f ( n ) f(n) f(n) 是一个函数, T ( n ) T(n) T(n) 是定义在非负整数上的递归式:
T ( n ) = a T ( n / b ) + f ( n ) T(n)=aT(n/b)+f(n) T(n)=aT(n/b)+f(n)
其中我们将 n / b n/b n/b 解释为 ⌊ n / b ⌋ \lfloor n/b \rfloor ⌊n/b⌋ 或 ⌈ n / b ⌉ \lceil n/b \rceil ⌈n/b⌉。那么 T ( n ) T(n) T(n) 有如下渐近界:- 若对某个常数 ε > 0 \varepsilon>0 ε>0 有 f ( n ) = O ( n l o g b a − ε ) f(n)=O(n^{log_ba-\varepsilon}) f(n)=O(nlogba−ε),则 T ( n ) = Θ ( n l o g b a ) T(n)=\Theta(n^{log_ba}) T(n)=Θ(nlogba)
- 若 f ( n ) = Θ ( n l o g b a ) f(n)=\Theta(n^{log_ba}) f(n)=Θ(nlogba),则 T ( n ) = Θ ( n l o g b a l g n ) T(n)=\Theta(n^{log_ba}lgn) T(n)=Θ(nlogbalgn)
- 若对某个常数 ε > 0 \varepsilon>0 ε>0 有 f ( n ) = Ω ( n l o g b a + ε ) f(n)=\Omega(n^{log_ba+\varepsilon}) f(n)=Ω(nlogba+ε),且对某个常数 c < 1 c<1 c<1 和足够大的 n n n 有 a f ( n / b ) ≤ c f ( n ) af(n/b)\leq cf(n) af(n/b)≤cf(n),则 T ( n ) = Θ ( f ( n ) ) T(n)=\Theta(f(n)) T(n)=Θ(f(n))
-
注意
主定理中的三种情况并未覆盖所有情况,在情况一和情况二中是存在间隙的,同样的,在情况二和情况三中也是存在间隙的,如果函数 f ( n ) f(n) f(n) 落在这两个间隙中,或者情况3的正则条件不成立,那么就不能使用主方法来求解递归式。
3.5 题目
-
证明: T ( n ) = T ( n − 1 ) + n T(n)=T(n-1)+n T(n)=T(n−1)+n 的解为 O ( n 2 ) O(n^2) O(n2)
假设 T ( n ) = O ( n 2 ) T(n)=O(n^2) T(n)=O(n2),则有: T ( n ) ≤ c n 2 T(n)\leq cn^2 T(n)≤cn2, T ( n − 1 ) ≤ c ( n − 1 ) 2 T(n-1)\leq c(n-1)^2 T(n−1)≤c(n−1)2
T ( n ) = T ( n − 1 ) + n ≤ c ( n − 1 ) 2 + n = c n 2 − ( 2 c − 1 ) n + c T(n)=T(n-1)+n \leq c(n-1)^2+n=cn^2-(2c-1)n+c T(n)=T(n−1)+n≤c(n−1)2+n=cn2−(2c−1)n+c
由上式:当 c ≥ 1 c\geq1 c≥1, n ≥ 1 n\geq 1 n≥1时, − ( 2 c − 1 ) n + c ≤ 0 -(2c-1)n+c \leq 0 −(2c−1)n+c≤0 恒成立,故此时, T ( n ) ≤ c n 2 T(n)\leq cn^2 T(n)≤cn2 恒成立 -
证明: T ( n ) = T ( ⌈ n / 2 ⌉ ) + 1 T(n)=T(\lceil n/2 \rceil)+1 T(n)=T(⌈n/2⌉)+1 的解为 O ( l g n ) O(lgn) O(lgn)
假设 T ( n ) = O ( l g n ) T(n)=O(lgn) T(n)=O(lgn),则有: T ( n ) ≤ c l g n T(n)\leq clgn T(n)≤clgn, T ( ⌈ n / 2 ⌉ ) ≤ c l g ( ⌈ n / 2 ⌉ ) T(\lceil n/2 \rceil) \leq clg(\lceil n/2 \rceil) T(⌈n/2⌉)≤clg(⌈n/2⌉)
T ( n ) = T ( ⌈ n / 2 ⌉ ) + 1 ≤ c l g ( ⌈ n / 2 ⌉ ) + 1 ≤ c l g ( n + 2 2 ) + 2 = c l g ( n + 2 ) − ( c − 1 ) T(n)=T(\lceil n/2 \rceil)+1 \leq clg(\lceil n/2 \rceil) + 1 \leq clg(\frac{n+2}2)+2=clg(n+2)-(c-1) T(n)=T(⌈n/2⌉)+1≤clg(⌈n/2⌉)+1≤clg(2n+2)+2=clg(n+2)−(c−1)
发现无法证明出来…假设 T ( n ) ≤ c l g ( n − 2 ) T(n)\leq clg(n-2) T(n)≤clg(n−2),则有 T ( ⌈ n / 2 ⌉ ) ≤ c l g ( ⌈ n / 2 ⌉ − 2 ) ≤ c l g ( n + 2 2 − 2 ) = c l g ( n − 2 2 ) = c l g ( n − 2 ) − c T(\lceil n/2 \rceil)\leq clg(\lceil n/2 \rceil -2)\leq clg(\frac{n+2}2-2)=clg(\frac{n-2}2)=clg(n-2)-c T(⌈n/2⌉)≤clg(⌈n/2⌉−2)≤clg(2n+2−2)=clg(2n−2)=clg(n−2)−c
T ( n ) = T ( ⌈ n / 2 ⌉ ) + 1 ≤ c l g ( n − 2 ) − c + 1 ≤ c l g ( n − 2 ) T(n)=T(\lceil n/2 \rceil)+1 \leq clg(n-2)-c+1 \leq clg(n-2) T(n)=T(⌈n/2⌉)+1≤clg(n−2)−c+1≤clg(n−2)
在 n > 2 n>2 n>2, c ≥ 1 c\geq1 c≥1时,上式成立即可推出 T ( n ) ≤ c l g ( n − 2 ) ≤ c l g n T(n)\leq clg(n-2)\leq clgn T(n)≤clg(n−2)≤clgn 在 n > 2 n>2 n>2, c ≥ 1 c \geq 1 c≥1 时成立,即 T ( n ) = O ( l g n ) T(n)=O(lgn) T(n)=O(lgn) 在此情况下成立
当 n = 2 n=2 n=2 , T ( 2 ) = 2 T(2)=2 T(2)=2
此时若要满足 T ( n ) ≤ c l g n T(n)\leq clgn T(n)≤clgn,则 T ( 2 ) = 2 ≤ c l g 2 = c T(2)=2\leq clg2=c T(2)=2≤clg2=c 可知 c ≥ 2 c\geq2 c≥2
综上所述,当 c ≥ 2 c\geq2 c≥2 且 n > = 2 n>=2 n>=2 时,满足 T ( n ) ≤ c l g n T(n)\leq clgn T(n)≤clgn,即 T ( n ) = O ( l g n ) T(n)=O(lgn) T(n)=O(lgn)
-
我们看到 T ( n ) = 2 T ( ⌊ n / 2 ⌋ ) + n T(n)=2T(\lfloor n/2 \rfloor)+n T(n)=2T(⌊n/2⌋)+n 的解为 O ( n l g n ) O(nlgn) O(nlgn)。证明 Ω ( n l g n ) \Omega(nlgn) Ω(nlgn) 也是这个递归式的解。从而得出结论:解为 Θ ( n l g n ) \Theta(nlgn) Θ(nlgn)
假设 T ( n ) = Ω ( n l g n ) ≥ c n l g n T(n)=\Omega(nlgn)\geq cnlgn T(n)=Ω(nlgn)≥cnlgn,则有 T ( ⌊ n / 2 ⌋ ) ≥ c ⌊ n / 2 ⌋ l g ( ⌊ n / 2 ⌋ ) T(\lfloor n/2 \rfloor)\geq c\lfloor n/2 \rfloor lg(\lfloor n/2 \rfloor) T(⌊n/2⌋)≥c⌊n/2⌋lg(⌊n/2⌋)
T ( n ) = 2 T ( ⌊ n / 2 ⌋ ) + n T(n)=2T(\lfloor n/2 \rfloor)+n T(n)=2T(⌊n/2⌋)+n
≥ 2 c ⌊ n / 2 ⌋ l g ( ⌊ n / 2 ⌋ ) + n \geq2c\lfloor n/2 \rfloor lg(\lfloor n/2 \rfloor)+n ≥2c⌊n/2⌋lg(⌊n/2⌋)+n
≥ c n l g ( n / 2 ) + n \geq cnlg(n/2)+n ≥cnlg(n/2)+n
≥ c n l g n − c n + n \geq cnlgn - cn + n ≥cnlgn−cn+n
≥ c n l g n − ( c − 1 ) n \geq cnlgn -(c-1)n ≥cnlgn−(c−1)n
≥ c n l g n \geq cnlgn ≥cnlgn
当 0 < c ≤ 1 0 < c \leq 1 0<c≤1 时,上式成立,即 T ( n ) = Ω ( n l g n ) T(n)=\Omega(nlgn) T(n)=Ω(nlgn)
因此,可得该递归式的解为 T ( n ) = Θ ( n l g n ) T(n)=\Theta(nlgn) T(n)=Θ(nlgn)
-
用主方法求 T ( n ) = 2 T ( n / 4 ) + 1 T(n)=2T(n/4)+1 T(n)=2T(n/4)+1 的紧确界
a = 2 , b = 4 , f ( n ) = 1 a=2,\;b=4,\;f(n)=1 a=2,b=4,f(n)=1
存在 ε = 1 2 \varepsilon=\frac12 ε=21 使得 f ( n ) = 1 = n l o g b a − ε = n l o g 4 2 − 1 2 f(n)=1=n^{log_ba-\varepsilon}=n^{log_42-\frac12} f(n)=1=nlogba−ε=nlog42−21,所以 T ( n ) = Θ ( n l o g b a ) = Θ ( n 1 2 ) = Θ ( n ) T(n)=\Theta(n^{log_ba})=\Theta(n^\frac12)=\Theta(\sqrt{n}) T(n)=Θ(nlogba)=Θ(n21)=Θ(n)
-
用主方法求 T ( n ) = 2 T ( n / 4 ) + n T(n)=2T(n/4)+\sqrt{n} T(n)=2T(n/4)+n
a = 2 , b = 4 , f ( n ) = n 1 2 a=2,\; b=4,\; f(n)=n^\frac12 a=2,b=4,f(n)=n21
f ( n ) = n 1 2 = n l o g b a = n l o g 4 2 = n 1 2 f(n)=n^\frac12=n^{log_ba}=n^{log_42}=n^\frac12 f(n)=n21=nlogba=nlog42=n21,故 T ( n ) = Θ ( n l o g b a l g n ) = Θ ( n l g n ) T(n)=\Theta(n^{log_ba}lgn)=\Theta(\sqrt{n}lgn) T(n)=Θ(nlogbalgn)=Θ(nlgn)
-
用主方法求 T ( n ) = 2 T ( n / 4 ) + n T(n)=2T(n/4)+n T(n)=2T(n/4)+n 的紧确界
a = 2 , b = 4 , f ( n ) = n a=2,\; b=4,\; f(n)=n a=2,b=4,f(n)=n
存在 ε = 1 2 \varepsilon=\frac12 ε=21 使得 f ( n ) = n = n l o g b a + ε = n l o g 4 2 + 1 2 f(n)=n=n^{log_ba+\varepsilon}=n^{log_42+\frac12} f(n)=n=nlogba+ε=nlog42+21
又: a f ( n / b ) = 2 f ( n / 4 ) = n 2 af(n/b)=2f(n/4)=\frac{n}2 af(n/b)=2f(n/4)=2n
当 1 2 ≤ c < 1 \frac12 \leq c < 1 21≤c<1 时,对任意 n ≥ 1 n\geq1 n≥1 满足 a f ( n / b ) = n / 2 ≤ c f ( n ) = c n af(n/b)=n/2 \leq cf(n)=cn af(n/b)=n/2≤cf(n)=cn
所以 T ( n ) = Θ ( f ( n ) ) = Θ ( n ) T(n)=\Theta(f(n))=\Theta(n) T(n)=Θ(f(n))=Θ(n)
-
用主方法求 T ( n ) = 2 T ( n / 4 ) + n 2 T(n)=2T(n/4)+n^2 T(n)=2T(n/4)+n2 的紧确界
a = 2 , b = 4 , f ( n ) = n 2 a=2,\; b=4,\; f(n)=n^2 a=2,b=4,f(n)=n2
存在 ε = 3 2 \varepsilon=\frac32 ε=23 使得 f ( n ) = n 2 = n l o g b a + ε = n l o g 4 2 + 3 2 f(n)=n^2=n^{log_ba+\varepsilon}=n^{log_42+\frac32} f(n)=n2=nlogba+ε=nlog42+23
又: a f ( n / b ) = 2 f ( n / 4 ) = n 2 8 af(n/b)=2f(n/4)=\frac{n^2}8 af(n/b)=2f(n/4)=8n2
当 1 8 ≤ c < 1 \frac18\leq c < 1 81≤c<1 时,对任意 n ≥ 1 n \geq 1 n≥1 满足 a f ( n / b ) = n 2 8 ≤ c f ( n ) = c n 2 af(n/b)=\frac{n^2}8\leq cf(n) = cn^2 af(n/b)=8n2≤cf(n)=cn2
所以 T ( n ) = Θ ( f ( n ) ) = Θ ( n 2 ) T(n)=\Theta(f(n))=\Theta(n^2) T(n)=Θ(f(n))=Θ(n2)
-
主方法能应用于递归式 T ( n ) = 4 T ( n / 2 ) + n 2 l g n T(n)=4T(n/2)+n^2lgn T(n)=4T(n/2)+n2lgn 吗?请说明为什么可以或为什么不可以。给出这个递归式的渐近上界
a = 4 , b = 2 , f ( n ) = n 2 l g n a=4,\;b=2,\;f(n)=n^2lgn a=4,b=2,f(n)=n2lgn
有 n l o g b a = n 2 n^{log_ba}=n^2 nlogba=n2,该式置于情况2与情况3的间隙之中,无法使用主方法来求解
可用画递归树的方式来求得该式的渐近上界为 O ( ( n l g n ) 2 ) O((nlgn)^2) O((nlgn)2)
接着可以使用代入法来证明该解的正确性
假设 T ( n ) = O ( ( n l g n ) 2 ) T(n)=O((nlgn)^2) T(n)=O((nlgn)2),有 T ( n ) ≤ c ( n l g n ) 2 T(n) \leq c(nlgn)^2 T(n)≤c(nlgn)2, T ( n 2 ) = c n 2 ( l g n − 1 ) 2 T(\frac{n}2)=cn^2(lgn-1)^2 T(2n)=cn2(lgn−1)2
T ( n ) ≤ c n 2 ( l g n − 1 ) 2 + n 2 l g n = c ( n l g n ) 2 − 2 c n 2 l g n + c n 2 + n 2 l g n = c ( n l g n ) 2 − ( 2 c − 1 ) n 2 l g n + c n 2 T(n)\leq cn^2(lgn-1)^2+n^2lgn=c(nlgn)^2-2cn^2lgn+cn^2+n^2lgn=c(nlgn)^2-(2c-1)n^2lgn+cn^2 T(n)≤cn2(lgn−1)2+n2lgn=c(nlgn)2−2cn2lgn+cn2+n2lgn=c(nlgn)2−(2c−1)n2lgn+cn2
由于 n 2 l g n n^2lgn n2lgn 的增长速率大于 n 2 n^2 n2,故 当 c > 1 2 c>\frac12 c>21 时,必然存在 n 0 > 0 n_0>0 n0>0,使得当 n > n 0 n>n_0 n>n0时, − ( 2 c − 1 ) n 2 l g n + c n 2 ≤ 0 -(2c-1)n^2lgn+cn^2\leq0 −(2c−1)n2lgn+cn2≤0即此时 c ( n l g n ) 2 − ( 2 c − 1 ) n 2 l g n + c n 2 ≤ c ( n l g n ) 2 c(nlgn)^2-(2c-1)n^2lgn+cn^2 \leq c(nlgn)^2 c(nlgn)2−(2c−1)n2lgn+cn2≤c(nlgn)2
故: T ( n ) ≤ c ( n l g n ) 2 T(n) \leq c(nlgn)^2 T(n)≤c(nlgn)2
T ( n ) = O ( ( n l g n ) 2 ) T(n)=O((nlgn)^2) T(n)=O((nlgn)2) 得证
4、平摊分析方法
4.1 基本思想
求数据结构的一个操作序列中所执行的所有操作的平均时间,来评价操作的代价。摊还分析不同于平均情况分析,它并不涉及概率,它可以保证最坏情况下的每个操作的平均性能。
4.2 合计法(聚合分析)
利用聚合分析,我们证明对所有n,一个n个操作的序列最坏情况下花费的总时间是 T ( n ) T(n) T(n)。因此,在最坏情况下,每个操作的平均代价,或摊还代价为 T ( n ) / n T(n)/n T(n)/n
4.3 记账法(核算法)
用核算法进行摊还分析时,我们对不同操作赋予不同费用,该费用称为摊还代价。当一个操作的摊还代价超出实际代价时,则将差额存入特定对象,该差额称为信用,对于后续操作中摊还代价小于实际代价的情况时,就可以使用信用来支付差额。
因此,核算法是将一个操作的摊还代价分解为其实际代价和信用。
4.4 势函数方法
假设我们将对一个初始数据结构 D 0 D_0 D0 执行 n n n 个操作。对每个 i = 1 , 2 , . . . , n i=1,2,...,n i=1,2,...,n,令 c i c_i ci 为第 i i i 个操作的实际代价,令 D i D_i Di 为在数据结构 D i − 1 D_{i-1} Di−1 上执行第 i i i 个操作得到的结果数据结构。势函数 Φ \Phi Φ 将每个数据结构 D i D_i Di 映射到一个实数 Φ ( D i ) \Phi(D_i) Φ(Di),此值即为关联到数据结构 D i D_i Di 的势。第 i i i 个操作的摊还代价 c ^ i \hat{c}_i c^i 用势函数 Φ \Phi Φ 定义为:
c ^ i = c i + Φ ( D i ) − Φ ( D i − 1 ) \hat{c}_i=c_i+\Phi(D_i)-\Phi(D_{i-1}) c^i=ci+Φ(Di)−Φ(Di−1)
那么,总摊还代价为:
∑ i = 1 n c ^ i = ∑ i = 1 n ( c i + Φ ( D i ) − Φ ( D i − 1 ) ) = ∑ i = 1 n c i + Φ ( D n ) − Φ ( D 0 ) \sum_{i=1}^n\hat{c}_i=\sum_{i=1}^n(c_i+\Phi(D_i)-\Phi(D_{i-1}))=\sum_{i=1}^nc_i+\Phi(D_n)-\Phi(D_0) i=1∑nc^i=i=1∑n(ci+Φ(Di)−Φ(Di−1))=i=1∑nci+Φ(Dn)−Φ(D0)
4.5 动态表分析
5、算法正确性分析
5.1 循环不变式(*)
5.2 cut and paste方法
5.3 归纳法
5.4 贪心选择性质
四、最大流
1、流、流网络定义
-
流网络
流网络 G = ( V , E ) G=(V,E) G=(V,E) 是一个有向图,图中的每条边 ( u , v ) ∈ E (u, v)\in E (u,v)∈E 有一个非负的容量值 c ( u , v ) ≥ 0 c(u, v) \geq 0 c(u,v)≥0。而且,边集合 E E E 中若包含一条边 ( u , v ) (u,v) (u,v),则图中不存在反向边 ( v , u ) (v,u) (v,u),(ps: 若存在反向边,可以增加一个节点来消除反平行边)。
若 ( u , v ) ∉ E (u,v) \notin E (u,v)∈/E,则 c ( u , v ) = 0 c(u,v)=0 c(u,v)=0,图中不允许自循环。
s s s 为源点, t t t 为汇点
对于图中任意节点 v v v,存在 s ⇝ v ⇝ t s \leadsto v \leadsto t s⇝v⇝t,并且除源点外的每个节点都至少有一条进入的边,除了汇点外的每个节点都至少有一条出去的边。
-
流
设 G = ( V , E ) G=(V,E) G=(V,E) 是一个流网络,其容量函数为 c c c 。设 s s s 为网络中的源点, t t t 为网络中的汇点。 G G G 中的流是一个实值函数 f : V × V → R f:V \times V \rightarrow R f:V×V→R,并满足下列三条性质:
-
**容量限制:**对于所有的 u , v ∈ V u,v\in V u,v∈V,有 f ( u , v ) ≤ c ( u , v ) f(u,v)\leq c(u,v) f(u,v)≤c(u,v)
-
**反对称性:**对于所有的 u , v ∈ V u,v\in V u,v∈V,有 f ( u , v ) = − f ( v , u ) f(u,v)=-f(v,u) f(u,v)=−f(v,u)
-
**流量守恒:**对于所有的 u ∈ V − { s , t } u\in V-\{s,t\} u∈V−{s,t},有:
∑ u ∈ V f ( u , v ) = 0 \sum_{u\in V}f(u,v)=0 u∈V∑f(u,v)=0
一个流的值 ∣ f ∣ |f| ∣f∣ 的定义如下:
∣ f ∣ = ∑ v ∈ V f ( s , v ) − ∑ v ∈ V f ( v , s ) |f|=\sum_{v\in V}f(s,v)-\sum_{v\in V}f(v,s) ∣f∣=v∈V∑f(s,v)−v∈V∑f(v,s) -
2、Ford-Fulkerson方法
-
残存网络
假定有一个网络流 G = ( V , E ) G=(V,E) G=(V,E),其源点为 s s s,汇点为 t t t 。设 f f f 为图 G G G 中的一个流。考虑节点对 u , v ∈ V u,v\in V u,v∈V,定义残存容量 c f ( u , v ) c_f(u,v) cf(u,v) 为:
c f ( u , v ) = { c ( u , v ) − f ( u , v ) 若 ( u , v ) ∈ E f ( v , u ) 若 ( v , u ) ∈ E 0 其 他 c_f(u,v)=\left\{ \begin{aligned} c(u,v)-f(u,v)\;\;若(u,v)\in E \\ f(v,u)\qquad\qquad\;\;\,若(v,u)\in E \\ 0\qquad\;\qquad\qquad\qquad\qquad其他 \end{aligned} \right. cf(u,v)=⎩⎪⎨⎪⎧c(u,v)−f(u,v)若(u,v)∈Ef(v,u)若(v,u)∈E0其他
给定一个流网络 G G G 和一个流 f f f,则由 f f f 所诱导的图 G G G 的残存网络为 G f = ( V , E f ) G_f=(V,\;E_f) Gf=(V,Ef),其中:
E f = { ( u , v ) ∈ V × V : c f > 0 } E_f=\{(u,v)\in V\times V:c_f>0\} Ef={(u,v)∈V×V:cf>0}
在残存网络中将流量推送回去称为抵消操作 -
增广路经
给定流网络 G = ( V , E ) G=(V,\;E) G=(V,E) 和流 f f f,增广路径 p p p 是残存网络 G f G_f Gf 中一条从源节点 s s s,到汇点 t t t 的一条简单路径。
对于一条增广路径,我们能为它每条边增大的最大流量为路径 p p p 的残存容量:
c f ( p ) = m i n { c f ( u , v ) : ( u , v ) 属 于 路 径 p } c_f(p)=min\{c_f(u,v): \; (u,v) \; 属于路径 \; p\} cf(p)=min{cf(u,v):(u,v)属于路径p} -
流网络的切割
流网络 G = ( V , E ) G=(V,\;E) G=(V,E) 中的一个切割 ( S , T ) (S,\;T) (S,T) 将结点集合 V V V 划分为 S S S 和 T = V − S T=V-S T=V−S 两个集合,使得 s ∈ S , t ∈ T s\in S,\; t\in T s∈S,t∈T 。
-
基本Ford-Fulkerson算法
FORD-FULKERSON(G, s, t)
for each edge(u, v) in G, E:
(u, v).f = 0
while there exists a path p from s to t in the redidual network Gf:
c_f(p) = min{c_f(u, v): (u, v) is in p}
for each edge(u, v) in p:
if (u, v) in E:
(u, v).f = (u, v) + c_f(p)
else (v, u).f = (v, u).f - c_f(p)
6、相关算法及时间
Ford-Fulkerson算法的运行时间为 O ( E ∣ f ∗ ∣ ) O(E|f^*|) O(E∣f∗∣),其中 f ∗ f^* f∗ 为最大流的数量