排序算法之归并排序(附 Python 与 JS 实现)

740 阅读3分钟

文章同步发布于博客

从头开始复习算法有一段时间了,有输入也要有输出。除了交编程作业以外,也要整理自己的笔记。

归并排序,使用分治的思想,将原问题折半分解为子问题,再使用同样的算法解决子问题。

总体思路

  • 如果数组长度为 1,就返回该数组。
  • 如果不是 1,则将数组折半,对每一半执行归并排序,将排好序的数组存在两个变量里。
  • 之后,通过归并算法将两个数组拼合成一个排好序的数组。
  • 返回该排好序的数组。

递归过程中,数组会被逐层拆分,直到每一个子问题都变为长度为一的数组,此时,每一个子问题的数组都是排好序的了(因为就一个元素),就会触发拼合操作。

将两个已排好序的数组拼合的过程如下:

  • 创建一个长度为两数组长度之和的空数组。
  • 比较两个数组的头元素,将小的那个移至新数组非空部分的末尾。循环执行直至其中一个数组的元素全部被挪走。
  • 将剩余的部分按序挪至新数组的末尾。
  • 这样就得到了一个合并之后的排好序的数组。

再逐层递归执行合并操作,直到最后将原数组排好序。

伪代码:

MergeSort(A[1...n])
    if n == 1:
        return A
    m = floor(n/2)
    B = MergeSort(A[0...m])
    C = MergeSort(A[m+1...n])
    A' = Merge(B, C)
    return A'

Merge(B[1...p], C[1...q])
    // B and C are sorted
    D = empty array of size p+q
    while B and C are both not empty:
        b = B[0]
        c = C[0]
        if b <= c:
            move b to the end of D
        else:
            move c to the end of D
    // after the while loop, one of the two array is now empty
    move the rest of B or C to the end of D
    return D

Python 3 实现: 可以存储至本地文件然后运行查看结果

def MergeSort(A):
    if len(A) == 1:
        return A
    m = len(A) // 2
    B = MergeSort(A[0:m])
    C = MergeSort(A[m:len(A)])
    A_new = Merge(B, C)
    return A_new

def Merge(B, C):
    D = [None] * (len(B)+len(C))
    i = 0
    j = 0
    while i < len(B) and j < len(C):
        b = B[i]
        c = C[j]
        if b <= c:
            D[i+j] = b
            i += 1
        else:
            D[i+j] = c
            j += 1
    while i < len(B):
        D[i+j] = B[i]
        i += 1
    while j < len(C):
        D[i+j] = C[j]
        j += 1
    return D

if __name__ == '__main__':
    a = [1, 3, 7, 2, 9, 6, 8, 10, 1, 2, 5]
    sorted_A = MergeSort(a)
    print(sorted_A)

JavaScript 实现 同样可以保存文件,然后通过 node 命令运行

function mergeSort(array) {
  if (array.length === 1)
    return array
  let m = Math.floor(array.length / 2)
  let B = mergeSort(array.slice(0, m))
  let C = mergeSort(array.slice(m, array.length))
  let A_sorted = merge(B, C)

  return A_sorted;
}

function merge(B, C) {
  let i = 0
  let j = 0
  let D = []
  while(i < B.length && j < C.length){
    if (B[i] <= C[j]){
      D.push(B[i++])
    } else {
      D.push(C[j++])
    }
  }
  while (i < B.length) D.push(B[i++])
  while (j < C.length) D.push(C[j++])

  return D
}

let a = mergeSort([1, 4, 2, 8, 345, 123, 43, 32, 5643, 63, 123, 43, 2, 55, 1, 234, 92]);
console.log(a)