(1)算法简介
归并排序是一种稳定的排序算法,采用分治策略,将待排序的数组分成若干子数组,分别对每个子数组进行排序,再将这些子数组合并成一个有序数组。归并排序的时间复杂度为 O(nlogn),在数据量较大且对排序稳定性要求较高的场景中有较好的表现。
同样,我们接下来带着你边学如何实现排序算法边理解该算法的内核。
(2)算法的原理与步骤
归并排序的基本思想是将数组分成尽可能小的子数组(每个子数组只有一个元素),然后逐步合并这些子数组,使得合并后的数组有序。具体步骤如下:
分割: 将数组分成两部分,递归地对每一部分进行归并排序。
排序并合并: 当每个子数组的长度为1时,开始合并相邻的子数组。在合并时,使用双指针技术,比较两个子数组的元素,将较小的元素放入临时数组中。
递归处理: 对左右子数组分别递归应用归并排序,直至最终将所有元素合并为一个有序数组。
——看完了上述大体如何实现归并排序算法之后,让我们从代码的层面来实现一下快速排序算法。
(3)Java代码实现
以下为Java中实现归并排序的大致代码:
public void mergeSort(int[] array) {
// 调用归并排序的递归方法,排序整个数组
mergeInsertSort(array, 0, array.length - 1);
}
public void mergeInsertSort(int[] array, int left, int right) {
// 如果子数组只有一个元素或为空,则返回(递归终止条件)
if (left >= right) {
return;
}
// 计算中间位置,将数组分成两部分
int mid = (left + right) / 2;
// 对左半部分进行递归排序
mergeInsertSort(array, left, mid);
// 对右半部分进行递归排序
mergeInsertSort(array, mid + 1, right);
// 合并两个已排序的子数组
merge(array, left, mid, right);
}
public void merge(int[] array, int left, int mid, int right) {
// 右半部分的起始位置
int rightBegin = mid + 1;
// 左半部分的起始位置
int leftBegin = left;
// 用于存放合并结果的临时数组
int i = 0;
int[] ret = new int[right - left + 1];
// 合并两个已排序的子数组
while (left <= mid && rightBegin <= right) {
// 比较左右两部分的元素,将较小的元素放入临时数组
if (array[left] < array[rightBegin]) {
ret[i++] = array[left++];
} else {
ret[i++] = array[rightBegin++];
}
}
// 将左半部分剩余的元素添加到临时数组中
while (left <= mid) {
ret[i++] = array[left++];
}
// 将右半部分剩余的元素添加到临时数组中
while (rightBegin <= right) {
ret[i++] = array[rightBegin++];
}
// 将临时数组中的元素复制回原数组的相应位置
for (int j = 0; j < ret.length; j++) {
array[j + leftBegin] = ret[j];
}
}
解释:
mergeSort(int[] array):这是归并排序的入口方法,它调用 mergeInsertSort 方法对整个数组进行排序。
mergeInsertSort(int[] array, int left, int right):这是归并排序的递归方法,递归地将数组分成更小的部分并排序,然后调用 merge 方法合并已排序的子数组。
merge(int[] array, int left, int mid, int right):这是合并两个已排序的子数组的方法。它创建一个临时数组 ret,将左右两部分按顺序合并到 ret 中,然后将合并后的结果复制回原数组。
——这样我们就了解了如何使用Java代码来实现归并排序算法。
(4)时间复杂度和空间复杂度
时间复杂度: O(nlogn)。每次分割将数组对半分,深度为 O(logn),合并过程需要遍历整个数组,因此时间复杂度为 O(nlogn)。
空间复杂度: O(n)。归并排序需要额外的空间来存储临时数组,用于合并过程中临时存放子数组的元素。
(5)算法的应用场景
归并排序的稳定性和时间复杂度使其适用于以下场景:
稳定性要求高的排序: 归并排序是一种稳定排序算法,适用于对相同值的元素相对顺序有要求的场景。
外部排序: 归并排序适用于处理超大数据集的外部排序,由于其稳定性和性能,尤其适用于磁盘文件的排序操作。
数据集较大且未全部加载到内存: 在处理大规模数据时,归并排序由于其分割和合并的特性,可以有效地处理不能一次性加载到内存的数据。
——这样我们学习完了如何在Java中实现归并算法。