一、思想
归并排序的核心思想是分治法,即将大问题分解成小问题来解决,然后再将解决后的小问题的结果合并以解决原来的大问题。具体包括以下几个步骤:
- 分解(Divide):将原始数组不断地二分成更小的子数组,直到每个子数组只包含一个元素,即认为它们已经有序。
- 解决(Conquer):递归地对这些子数组应用归并排序,一旦子数组被拆分到只含有一个元素,就开始对其进行两两合并。
- 合并(Combine):将两个已经排序的子数组合并成一个有序的数组。这一过程通常涉及比较两个子数组的最前端元素,选择较小的一个放入新的合并后的数组,并移动指针到下一个位置,重复此过程直至所有元素被合并。
归并排序是一种稳定的排序算法,适用于大数据量时效率较高,且可以用于链表等数据结构的排序。然而,它的不足之处在于需要额外的存储空间来存放临时数组,并且对于小规模数据的排序效率不如某些简单的排序算法,如插入排序。此外,由于其递归的特性,归并排序在深度很大的情况下可能会导致调用栈溢出。
二、图解
图解
对于一个这样的数组,首先我们需要将这个数组不断的划分为两个子数组
分解代码如下
然后将这些子数组逐个排序合并
合并代码如下:
整体图示如下:
三、代码实现
void merger_sort(vector<int>& arr, int l, int r) {if (l >= r) return;int mid = (l + r) / 2;merger_sort(arr, l, mid);merger_sort(arr, mid + 1, r);int k = 0, s1 = l, s2 = mid + 1;vector<int> t(r - l + 1);while (s1 <= mid && s2 <= r) {if (arr[s1] < arr[s2]) t[k++] = arr[s1++];else t[k++] = arr[s2++];}while (s1 <= mid) t[k++] = arr[s1++];while (s2 <= r) t[k++] = arr[s2++];for (int i = 0; i < k; i++) arr[i + l] = t[i];
}
public static void mergerSort(int[] arr, int l, int r) {if (l >= r) return; // 如果只有一个元素则结束分解int mid = (l + r) / 2; // 计算中间下标mergerSort(arr, l, mid); // 继续分解左边mergerSort(arr, mid + 1, r); // 继续分解右边int s1 = l, s2 = mid + 1, k = 0; // 开始合并int[] t = new int[r - l + 1];while (s1 <= mid && s2 <= r) {if (arr[s1] < arr[s2]) {t[k++] = arr[s1++];} else {t[k++] = arr[s2++];}}while (s1 <= mid) {t[k++] = arr[s1++];}while (s2 <= r) {t[k++] = arr[s2++];}// 将中间数组的值赋值给原数组for (int i = 0; i < k; i++) {arr[i + l] = t[i];}}