归并排序

归并排序

归并排序是基于分而治之算法的原理。把一个问题被划分为多个独立的子问题,再对每个子问题作同样的划分,直到base case无法再分时处理base case问题即可。最后,将子问题一层层合并起来形成最终解决方案。

-w500

假设我们必须对数组 A 进行排序,定义一个子问题是对这个数组的一个子部分进行排序,例如从索引 p 开始到索引 r 结束,表示为 A[p..r]。

-w600

步骤

划分 如果 q 是 p 和 r 的中间点,那么我们可以将子数组 A[p..r] 拆分为两个数组 A[p..q] 和 A[q+1, r]。

处理 在处理步骤中,我们尝试对子数组 A[p..q] 和 A[q+1, r] 进行排序。 如果还没有达到base case,就再次划分这两个子数组并尝试对它们进行排序。

合并 当处理到达base step,并且我们得到数组 A[p..r] 的两个排序子数组 A[p..q] 和 A[q+1, r] 时,通过创建一个排序数组 A[p..r] 来合并来自两个已排序的子数组 A[p..q] 和 A[q+1, r]的结果。

图示合并的过程

以下数组 A[0..5] 包含两个已排序的子数组 A[0..3] 和 A[4..5] -w300

创建子数组的副本以进行合并 -w300

定义3个索引指针来操作子数组与合并的数组 -w600

两数组合并过程 -w600

剩余元素追加的过程 -w500 -w500

复杂度

|Time Complexity|| |—|—| |Best | O(nlog n) | |Worst | O(nlog n) | |Average | O(n*log n) | |Space Complexity | O(n) | |Stability | Yes |

代码实现

Swift 实现

import Foundation

//对数组在 l..r 区间的元素作归并排序,左闭右开
func mergeSort(array:inout [Int],l:Int,r:Int) {
    if l < r {
        //取中点,把在 l..r 区间的数组元素分成两个子数组
        let m = l + (r - l) / 2
        
        //对两个子数组分别作同样的归并排序
        mergeSort(array: &array, l: l, r: m)
        mergeSort(array: &array, l: m+1, r: r)
        
        //合并已排好序的子数组
        merge(array: &array, l:l, m:m, r:r)
    }
}


func merge(array:inout [Int],l:Int, m:Int, r:Int) {
    //创建两个子数组:L: a1[l..m] 和 a2: A[m+1..r]
    let n1 = m - l + 1
    let n2 = r - m
    
    //数组赋值
    let a1 = [Int](https://luowei.github.io/list/array[l ... m])
    let a2 = [Int](https://luowei.github.io/list/array[m+1 ... r])
    
    //var a1 = [Int](https://luowei.github.io/list/repeating: 0, count: n1)
    //var a2 = [Int](https://luowei.github.io/list/repeating: 0, count: n2)
    //var a1_i=0,a2_i=0
    //while a1_i < n1 {
    //    a1[a1_i] = array[l+a1_i]
    //    a1_i+=1
    //}
    //while a2_i < n2 {
    //    a2[a2_i] = array[m+1+a2_i]
    //    a2_i+=1
    //}
    
    //合并两个子数组,重叠区间部分,用两个指针(i,j)轮换比较处理
    var i=0,j=0,k=l
    while i < n1 && j < n2 {
        if a1[i] <= a2[j] {
            array[k] = a1[i]
            i+=1
        }else{
            array[k] = a2[j]
            j+=1
        }
        k+=1
    }
    
    //超出区间部分追加上
    while i < n1 {
        array[k] = a1[i]
        i+=1
        k+=1
    }
    while j < n2 {
        array[k] = a2[j]
        j+=1
        k+=1
    }

}


//打印
func printMergeSortSort(_ array:inout [Int]){
    mergeSort(array: &array, l: 0, r: array.count-1)
    print(array)
}

var arr:[Int] = [3, 2, 5, 7, 1, 5, 4, 8, 11, 0]
printMergeSortSort(&arr)

Python实现

# MergeSort in Python


def mergeSort(array):
    if len(array) > 1:

        #  r is the point where the array is divided into two subarrays
        r = len(array)//2
        L = array[:r]
        M = array[r:]

        # Sort the two halves
        mergeSort(L)
        mergeSort(M)

        i = j = k = 0

        # Until we reach either end of either L or M, pick larger among
        # elements L and M and place them in the correct position at A[p..r]
        while i < len(L) and j < len(M):
            if L[i] < M[j]:
                array[k] = L[i]
                i += 1
            else:
                array[k] = M[j]
                j += 1
            k += 1

        # When we run out of elements in either L or M,
        # pick up the remaining elements and put in A[p..r]
        while i < len(L):
            array[k] = L[i]
            i += 1
            k += 1

        while j < len(M):
            array[k] = M[j]
            j += 1
            k += 1


# Print the array
def printList(array):
    for i in range(len(array)):
        print(array[i], end=" ")
    print()


# Driver program
if __name__ == '__main__':
    array = [6, 5, 12, 10, 9, 1]

    mergeSort(array)

    print("Sorted array is: ")
    printList(array)

Java 实现

// Merge sort in Java

class MergeSort {

  // Merge two subarrays L and M into arr
  void merge(int arr[], int p, int q, int r) {

    // Create L ← A[p..q] and M ← A[q+1..r]
    int n1 = q - p + 1;
    int n2 = r - q;

    int L[] = new int[n1];
    int M[] = new int[n2];

    for (int i = 0; i < n1; i++)
      L[i] = arr[p + i];
    for (int j = 0; j < n2; j++)
      M[j] = arr[q + 1 + j];

    // Maintain current index of sub-arrays and main array
    int i, j, k;
    i = 0;
    j = 0;
    k = p;

    // Until we reach either end of either L or M, pick larger among
    // elements L and M and place them in the correct position at A[p..r]
    while (i < n1 && j < n2) {
      if (L[i] <= M[j]) {
        arr[k] = L[i];
        i++;
      } else {
        arr[k] = M[j];
        j++;
      }
      k++;
    }

    // When we run out of elements in either L or M,
    // pick up the remaining elements and put in A[p..r]
    while (i < n1) {
      arr[k] = L[i];
      i++;
      k++;
    }

    while (j < n2) {
      arr[k] = M[j];
      j++;
      k++;
    }
  }

  // Divide the array into two subarrays, sort them and merge them
  void mergeSort(int arr[], int l, int r) {
    if (l < r) {

      // m is the point where the array is divided into two subarrays
      int m = (l + r) / 2;

      mergeSort(arr, l, m);
      mergeSort(arr, m + 1, r);

      // Merge the sorted subarrays
      merge(arr, l, m, r);
    }
  }

  // Print the array
  static void printArray(int arr[]) {
    int n = arr.length;
    for (int i = 0; i < n; ++i)
      System.out.print(arr[i] + " ");
    System.out.println();
  }

  // Driver program
  public static void main(String args[]) {
    int arr[] = { 6, 5, 12, 10, 9, 1 };

    MergeSort ob = new MergeSort();
    ob.mergeSort(arr, 0, arr.length - 1);

    System.out.println("Sorted array:");
    printArray(arr);
  }
}

C 实现

// Merge sort in C

#include <stdio.h>

// Merge two subarrays L and M into arr
void merge(int arr[], int p, int q, int r) {

  // Create L ← A[p..q] and M ← A[q+1..r]
  int n1 = q - p + 1;
  int n2 = r - q;

  int L[n1], M[n2];

  for (int i = 0; i < n1; i++)
    L[i] = arr[p + i];
  for (int j = 0; j < n2; j++)
    M[j] = arr[q + 1 + j];

  // Maintain current index of sub-arrays and main array
  int i, j, k;
  i = 0;
  j = 0;
  k = p;

  // Until we reach either end of either L or M, pick larger among
  // elements L and M and place them in the correct position at A[p..r]
  while (i < n1 && j < n2) {
    if (L[i] <= M[j]) {
      arr[k] = L[i];
      i++;
    } else {
      arr[k] = M[j];
      j++;
    }
    k++;
  }

  // When we run out of elements in either L or M,
  // pick up the remaining elements and put in A[p..r]
  while (i < n1) {
    arr[k] = L[i];
    i++;
    k++;
  }

  while (j < n2) {
    arr[k] = M[j];
    j++;
    k++;
  }
}

// Divide the array into two subarrays, sort them and merge them
void mergeSort(int arr[], int l, int r) {
  if (l < r) {

    // m is the point where the array is divided into two subarrays
    int m = l + (r - l) / 2;

    mergeSort(arr, l, m);
    mergeSort(arr, m + 1, r);

    // Merge the sorted subarrays
    merge(arr, l, m, r);
  }
}

// Print the array
void printArray(int arr[], int size) {
  for (int i = 0; i < size; i++)
    printf("%d ", arr[i]);
  printf("\n");
}

// Driver program
int main() {
  int arr[] = {6, 5, 12, 10, 9, 1};
  int size = sizeof(arr) / sizeof(arr[0]);

  mergeSort(arr, 0, size - 1);

  printf("Sorted array: \n");
  printArray(arr, size);
}

C++ 实现

// Merge sort in C++

#include <iostream>
using namespace std;

// Merge two subarrays L and M into arr
void merge(int arr[], int p, int q, int r) {
  
  // Create L ← A[p..q] and M ← A[q+1..r]
  int n1 = q - p + 1;
  int n2 = r - q;

  int L[n1], M[n2];

  for (int i = 0; i < n1; i++)
    L[i] = arr[p + i];
  for (int j = 0; j < n2; j++)
    M[j] = arr[q + 1 + j];

  // Maintain current index of sub-arrays and main array
  int i, j, k;
  i = 0;
  j = 0;
  k = p;

  // Until we reach either end of either L or M, pick larger among
  // elements L and M and place them in the correct position at A[p..r]
  while (i < n1 && j < n2) {
    if (L[i] <= M[j]) {
      arr[k] = L[i];
      i++;
    } else {
      arr[k] = M[j];
      j++;
    }
    k++;
  }

  // When we run out of elements in either L or M,
  // pick up the remaining elements and put in A[p..r]
  while (i < n1) {
    arr[k] = L[i];
    i++;
    k++;
  }

  while (j < n2) {
    arr[k] = M[j];
    j++;
    k++;
  }
}

// Divide the array into two subarrays, sort them and merge them
void mergeSort(int arr[], int l, int r) {
  if (l < r) {
    // m is the point where the array is divided into two subarrays
    int m = l + (r - l) / 2;

    mergeSort(arr, l, m);
    mergeSort(arr, m + 1, r);

    // Merge the sorted subarrays
    merge(arr, l, m, r);
  }
}

// Print the array
void printArray(int arr[], int size) {
  for (int i = 0; i < size; i++)
    cout << arr[i] << " ";
  cout << endl;
}

// Driver program
int main() {
  int arr[] = {6, 5, 12, 10, 9, 1};
  int size = sizeof(arr) / sizeof(arr[0]);

  mergeSort(arr, 0, size - 1);

  cout << "Sorted array: \n";
  printArray(arr, size);
  return 0;
}

版权所有,转载请注明出处 luowei.github.io.