算法笔记-分治法

Posted by MaggicQ on May 29, 2017

分治法

主定理

对于通用分治递推式: $T(n) = aT(n/b) + f(n)$

那么:

主定理

合并排序

对于一个需要排序的数组,合并排序将它一分为二,并对每个子数组递归排序,然后把这两个排好序的子数组

组合并为一个有序数组。

合并排序

其中 $Merge$ 函数是将两个有序数据进行合并:

合并操作

复杂度分析:

键值比较次数 $C(n)$

当 $n > 1$ 时, $C(n) = 2C(n/2) + C_{merge}(n) , C(1) = 0$

令 $ n = 2^k$ ,容易求得:

$C_{worst}(n) = nlog_2n - n + 1$

快速排序

快速排序按照元素的值对它们进行划分,建立了一个划分以后,$A[s]$ 已经位于它在有序数组中的最终位置,

接下来我们可以继续对 $A[s]$ 前和 $A[s]$后的子数组进行排序。

快速排序_伪代码

最优效率:

此时每次划分都可以恰好将数组分成大小相同的两部分,容易得到

当 $n>1$ 时, $C_{best}(n) = 2C_{best}(n/2) + n , C_{best}(1) = 0$

对于 $n = 2^k$ 的情况, $C_{best}(n) = nlog_2n$

最差的效率:

已经是严格递增的数组了,

$C_{worst}(n) \in \Theta(n^2)$

快速排序有一个重要的特点是,它的平均效率只比最优情况多执行39%的操作,

这使得它在实际中应用很广泛。

二叉树遍历及其相关特性

把二叉树定义为若干节点的一个有限集合,它要么为空,要么由一个根和两棵树称为

$T_L$ 和 $T_R$ 的不相交二叉树构成,这两科二叉树分别为根的左右子树。

计算二叉树的高度_分治法

除此之外,二叉树的遍历也蕴含这分治的思想,

前序遍历,中序遍历,后序遍历。

大整数乘法和 Strassen矩阵乘法

这两个算法都通过巧妙地运用分治技术来获得更好的渐进效率。

大整数乘法

应用:密码技术里面经常需要对超过100位的十进制整数进行乘法计算。

对于两个大整数 $a = a_1a_0 , b = b_1b_0$

其中 $a = a_110^{(n/2)} + a_0$

大整数相乘

其中 $c_2 = a_1 \times b_1$

$c_0 = a_0 \times b_0$

$c_1 = (a_1 + a_0) \times (b_1 + b_0) - (c_2 + c_0)$

这样$n$位数的乘法需要对 $n/2$位数做三位乘法运算,乘法次数$M(n)$的递推式如下:

$n> 1 时, M(n) = 3M(n/2), M(1) = 1$

当$n = 2^k时, M(2^k) = 3^k$

所以$M(n) = 3^{log_2n} $

Strassen矩阵乘法

计算两个 $2 \times 2$矩阵乘积:

矩阵乘法

计算两个$n$个方阵时执行的乘法次数:

$n > 1, M(n) = 7M(n/2) , M(1) =1$

用分治法解最近对问题和凸包问题

解决最近对问题

$ 2 \leq n \leq 3 $: 使用 蛮力算法进行求解

$n > 3$ : 可以利用点集在 $x$ 轴方向上的中位数 $m$ ,在该处

做一条垂线,将点集分文两个子集,然后对两个子集分别求求解,

注意合并的时候,还应该考虑到最近的两个点可能分别位于分界线的两侧,

因此在合并较小子问题的解的时候,需要检查是否存在这样的点。

最近对问题_分治法

最近对问题_分治法2

复杂度: $T(n) \in \Theta(nlogn)$

凸包问题