图解归并排序(Java + Python实现)

95 阅读2分钟

归并排序

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

归并排序是一种稳定的排序方法。

时间复杂度:最好时间复杂度很最坏时间复杂度都是 O ( N log ⁡ N ) O(N \log N) O(NlogN)。

归并排序的思想并不能理解,下面我们通过一个例子直观的看一下归并排序中"分"和"归"的具体过程。假设现在待排序数组为 [ 1 , 8 , 2 , 5 , 7 , 3 ] [1,8,2,5,7,3] [1,8,2,5,7,3],归并排序的整体过程如下所示:
在这里插入图片描述

分的过程就是不断的进行分解,直到数组元素只有一个。接下来具体看一下最后一次归并的具体过程,设置两个指针left和right分别指向两个待归并子数组的起始位置,并申请临时数组保存此轮归并的结果;当排序结束后将临时数组元素逐个复制到原始数组即可。
在这里插入图片描述

了解了归并排序的整体流程后,下面给出实现代码:

// Java实现
public class MergeSort {

	public static void mergeSort(int[] arr) {
		if (arr == null || arr.length < 2) {
			return;
		}
		mergeSort(arr, 0, arr.length - 1);
	}

	public static void mergeSort(int[] arr, int l, int r) {
		// 递归出口,当只有一个元素时返回
		if (l == r) {
			return;
		}

		int mid = l + ((r - l) >> 1);
		// 左半个数组排序
		mergeSort(arr, l, mid);
		// 右半个数组排序
		mergeSort(arr, mid + 1, r);
		// 归并有序数组
		merge(arr, l, mid, r);
	}

	// 归并过程
	// 申请额外的数组,设置两个指针分别指向两个子数组的起始位置
	// 选择两个指针指向的较小元素放入数组,更新指针,直到一个数组访问结束
	// 最后将剩下的元素直接放入额外数组的后面即可
	public static void merge(int[] arr, int l, int m, int r) {
		int[] help = new int[r - l + 1];
		int i = 0;
		int p1 = l;
		int p2 = m + 1;
		while (p1 <= m && p2 <= r) {
			help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
		}
		while (p1 <= m) {
			help[i++] = arr[p1++];
		}
		while (p2 <= r) {
			help[i++] = arr[p2++];
		}

		// 最后将额外数组中元素复制到原数组中
		for (i = 0; i < help.length; i++) {
			arr[l + i] = help[i];
		}
	}

Python实现:

class MergeSort:
    def __init__(self, arr):
        self.arr = arr
    
    def sort(self):
        if len(self.arr) < 2: return

        self.mergeSort(self.arr, 0, len(self.arr) - 1)
        print(self.arr)
    
    def mergeSort(self, arr, left, right):
        if left == right: return

        middle = left + ((right - left) // 2)
        self.mergeSort(arr, left, middle)
        self.mergeSort(arr, middle + 1, right)

        self.merge(arr, left, middle, right)

    def merge(self, arr, left, middle, right):
        array = []
        p, q = left, middle + 1

        while p <= middle and q <= right:
            if arr[p] < arr[q]:
                array.append(arr[p])
                p += 1
            else:
                array.append(arr[q])
                q += 1
        
        while p <= middle:
            array.append(arr[p])
            p += 1
        
        while q <= right:
            array.append(arr[q])
            q += 1
        
        for i in range(len(array)):
            self.arr[left + i] = array[i]

if __name__ == "__main__":
    a = [1,8,6,5,7,3]
    MergeSort(a).sort()