算法导论CLRS项目解析:第二章分治算法精讲

算法导论CLRS项目解析:第二章分治算法精讲

CLRS 📚 Solutions to Introduction to Algorithms Third Edition CLRS 项目地址: https://gitcode.com/gh_mirrors/clr/CLRS

归并排序的直观演示

归并排序(Merge Sort)是分治算法的经典案例。让我们通过一个具体数组来观察其运行过程:

给定数组 A = [3, 41, 52, 26, 38, 57, 9, 49],归并排序的执行步骤如下:

  1. 分解阶段:将数组不断二分,直到每个子数组只包含一个元素

    [3] [41] [52] [26] [38] [57] [9] [49]
    
  2. 合并阶段:逐步合并已排序的子数组

    [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)时间复杂度。

递归版插入排序分析

将插入排序改写为递归形式:

  1. 基本情况:单元素数组已排序
  2. 递归情况:先排序前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²),因为:

  1. 找到位置后仍需移动Θ(n)个元素
  2. 元素移动的代价主导了算法复杂度

这说明了算法分析需要考虑所有操作,而不仅仅是主导操作。

两数之和问题的高效解法

给定集合S和目标x,判断是否存在两数之和等于x:

  1. 先排序S:Θ(n lg n)
  2. 对每个元素s_i,用二分查找在剩余元素中查找x-s_i:n×Θ(lg n)

总时间复杂度:Θ(n lg n) + n×Θ(lg n) = Θ(n lg n)

更优的双指针法:

  1. 排序后,设置头尾指针i和j
  2. 计算S[i]+S[j]
    • 若等于x,返回true
    • 若小于x,i++
    • 若大于x,j--
  3. 直到i≥j

同样保持Θ(n lg n)时间复杂度,但实际运行更快。

通过这些问题,我们深入理解了分治算法的设计思想和分析方法,这对掌握更复杂的算法至关重要。

CLRS 📚 Solutions to Introduction to Algorithms Third Edition CLRS 项目地址: https://gitcode.com/gh_mirrors/clr/CLRS

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

翁然眉Esmond

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值