天天看点

算法入门——插入排序和归并排序

算法入门——插入排序和归并排序

新手算法入门,萌新一枚,如有错误,请多见谅!内容主要来源于《算法导论》。
           

插入排序

插入排序,主要适用于少量元素的排序,就像打扑克一样,左手拿已经排好的牌组,右手从待排序的牌堆中拿取一张,从右往左依次比较,找到合适位置时停下,插入,此牌右边的牌在排序过程中顺次右移一位。算法复杂度为Θ( n 2 n^2 n2)。

伪代码如下(将 A 数组递增输出):

INSERTION-SORT(A):
     for j = 2 to A.length:
         key = A[j]
         //Insert the A[j] into the sorted A[1..j-1]
         i = j - 1
         while i >0 and A[j] > key 
             A[i+1] = A[i]
             i = i -1
         A[i] = A[j]
  
           

归并排序

适用于规模较大的排序问题算法复杂度为Θ( n ∗ l o g 2 n n*log_2{n} n∗log2​n)
归并算法遵循分治法,在算法结构上是递归的,遵循3个步骤
  1. 分解:原问题分为若干子问题,这些问题是原问题的规模较小的实例。
  2. 解决:这些子问题,递归地求解各子问题。然而,各子问题的规模较小,可以直接求解。
  3. 合并:合并两个已排序的子序列以产生已排序的答案。
归并算法完全遵循分治法,
  1. 分解:分解待排序的n个元素的序列成各具n/2个元素的两个子序列。
  2. 解决:使用归并排序递归地排序两个子序列。
  3. 合并:合并两个已排序好的子序列以产生已排序好的答案。

归并算法的关键在于‘合并’步骤中合并两个已排序好的子序列以产生已排序好的答案。通过调用一个辅助过程MERGE(A,p,q,r)完成合并,其中A是一个数组,A[p,q]和A[q+1,r]已经完成排序,它合并这两个数组形成一个单一的已排好序的子数组来代替A[p,r]

同样以打扑克为例,假设桌面有两堆已经排好序牌面朝上的牌,面朝上,最小的牌在顶上。我们希望将这两堆牌合并成单一的排好序的输出堆,牌面朝下地放在桌上。

我们的基本步骤包括在牌面朝上的两堆牌的顶上两张牌选取最小的一张,将该牌从其堆中移开(该堆的顶上将露出一张新牌),并牌面朝下地放在输出堆中。重复这个步骤,直到一个输入堆为空。这时我们只需将另一堆牌面朝下地放置到输出堆中。

由于需要判定输入堆何时为空,因此我们在每个堆底部放置一张哨兵牌,因为递增输出,将 ∞ ∞ ∞最为哨兵值,则不可能有比哨兵牌更大的牌,由于程序共进行(r-p+1)次抽牌,哨兵牌不会被抽中。

以下是合并操作的代码:`MERGE(A,p,q,r)
MERGE(A,p,q,r)
    n1 = q - p + 1
    n2 = r - q
    let L[1,n1 + 1] and R[1,n2 + 1] be new arrays
    for i = 1 to n1
        L[i] = A[p + i - 1]
    for j = 1 to n2
        R[j] = A[q + i]
    L[i + 1] = ∞
    R[j + 1] = ∞
    i = 1
    j = 1
    for k = p to r
        if L[i] <= R[j]
            A[k] = L[i]
            i = i + 1
        else 
            A[k] = R[j]
            j = j + 1
            

           

现在我们可以将过程MERGE(A,p,q,r)作为归并算法的子程序使用。若p>=r,则该子数组中最多有一个元素所以已经排好序。否则分解步骤简单地计算一个下标q,将A[p…r]简单地分解为两个子数组A[p…q]和A[q+1…r]

下面是归并算法MERGE-SORT(A,p,r)的伪代码:

MERGE-SORT(A,p,r)
if p < r
    q = [(p+r)/2]
    MERGE-SORT(A,p,q)
    MERGE-SORT(A,q+1,r)
    MERGE(A,p,q,r)
           

继续阅读