算法导论CLRS项目解析:第二章分治算法精讲
归并排序的直观演示
归并排序(Merge Sort)是分治算法的经典案例。让我们通过一个具体数组来观察其运行过程:
给定数组 A = [3, 41, 52, 26, 38, 57, 9, 49],归并排序的执行步骤如下:
-
分解阶段:将数组不断二分,直到每个子数组只包含一个元素
[3] [41] [52] [26] [38] [57] [9] [49]
-
合并阶段:逐步合并已排序的子数组
[3,41] [26,52] [38,57] [9,49] ↓ [3,26,41,52] [9,38,49,57] ↓ [3,9,26,38,41,49,52,57]
这个过程完美展示了分治算法的核心思想:分解-解决-合并。
无特殊标记的归并实现
传统归并算法使用特殊标记(∞)来简化边界处理,但我们可以改进这一实现:
MERGE(A, p, q, r)
n1 = q - p + 1
n2 = r - q
创建新数组 L[1..n1] 和 R[1..n2]
for i = 1 to n1
L[i] = A[p + i - 1]
for j = 1 to n2
R[j] = A[q + j]
i = 1
j = 1
for k = p to r
if i > n1 // 左数组已全部处理
A[k] = R[j]
j = j + 1
else if j > n2 // 右数组已全部处理
A[k] = L[i]
i = i + 1
else if L[i] ≤ R[j]
A[k] = L[i]
i = i + 1
else
A[k] = R[j]
j = j + 1
这种实现通过显式检查数组边界,避免了特殊标记的使用,同时保持了相同的Θ(n)时间复杂度。
递归式的时间复杂度证明
对于递归式: $$ T(n) = \begin{cases} 2 & \text{当 } n = 2 \ 2T(n/2) + n & \text{当 } n = 2^k, k > 1 \end{cases} $$
我们可以用数学归纳法证明其解为T(n) = n lg n。
基例:n=2时,T(2)=2=2lg2成立。
归纳假设:假设对于n=2^k成立,即T(2^k)=2^k k。
归纳步骤:对于n=2^{k+1} $$ \begin{aligned} T(2^{k+1}) &= 2T(2^k) + 2^{k+1} \ &= 2·2^k k + 2^{k+1} \ &= 2^{k+1}(k+1) \ &= 2^{k+1} \lg 2^{k+1} \end{aligned} $$
这证明了归并排序在n为2的幂时的Θ(n lg n)时间复杂度。
递归版插入排序分析
将插入排序改写为递归形式:
- 基本情况:单元素数组已排序
- 递归情况:先排序前n-1个元素,再插入第n个元素
对应的递归式为: $$ T(n) = \begin{cases} Θ(1) & n=1 \ T(n-1) + Θ(n) & n>1 \end{cases} $$
展开递归树可见,总时间为Θ(1)+Θ(2)+...+Θ(n)=Θ(n²),与迭代版本一致。
二分查找算法详解
二分查找针对已排序数组,通过每次比较将搜索范围减半:
迭代实现:
ITERATIVE-BINARY-SEARCH(A, v, low, high)
while low ≤ high
mid = floor((low + high)/2)
if v == A[mid]
return mid
else if v > A[mid]
low = mid + 1
else
high = mid - 1
return NIL
递归实现:
RECURSIVE-BINARY-SEARCH(A, v, low, high)
if low > high
return NIL
mid = floor((low + high)/2)
if v == A[mid]
return mid
else if v > A[mid]
return RECURSIVE-BINARY-SEARCH(A, v, mid+1, high)
else
return RECURSIVE-BINARY-SEARCH(A, v, low, mid-1)
时间复杂度分析: $$ T(n) = T(n/2) + Θ(1) ⇒ T(n) = Θ(\lg n) $$
插入排序优化思考
虽然可以在插入排序中使用二分查找(Θ(lg n))来定位插入位置,但实际时间复杂度仍为Θ(n²),因为:
- 找到位置后仍需移动Θ(n)个元素
- 元素移动的代价主导了算法复杂度
这说明了算法分析需要考虑所有操作,而不仅仅是主导操作。
两数之和问题的高效解法
给定集合S和目标x,判断是否存在两数之和等于x:
- 先排序S:Θ(n lg n)
- 对每个元素s_i,用二分查找在剩余元素中查找x-s_i:n×Θ(lg n)
总时间复杂度:Θ(n lg n) + n×Θ(lg n) = Θ(n lg n)
更优的双指针法:
- 排序后,设置头尾指针i和j
- 计算S[i]+S[j]
- 若等于x,返回true
- 若小于x,i++
- 若大于x,j--
- 直到i≥j
同样保持Θ(n lg n)时间复杂度,但实际运行更快。
通过这些问题,我们深入理解了分治算法的设计思想和分析方法,这对掌握更复杂的算法至关重要。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考