1. 引言
在本教程中,我们将了解合并排序算法及其在 Java 中的实现。
合并排序是最有效的排序技术之一,它基于“分而治之”的范式。
2. 算法
**合并排序是一种“分而治之”的算法,我们首先将问题划分为子问题。**当子问题的解决方案准备就绪时,我们将它们组合在一起以获得问题的最终解决方案。
我们可以使用递归轻松实现此算法,因为我们处理的是子问题而不是主要问题。
我们可以将该算法描述为以下 2 步过程:
**除法:在此步骤中,我们将输入数组分成两半,**枢轴是数组的中点。此步骤以递归方式对所有半数组执行,直到没有更多的半数组要分割。
征服:在此步骤中,我们将分割后的数组从下到上排序并合并,并得到排序后的数组。
下图显示了示例数组 {10, 6, 8, 5, 7, 3, 4} 的完整合并排序过程。
如果我们仔细看一下图表,我们可以看到数组被递归地分成两半,直到大小变为 1。一旦大小变为 1,合并过程就会开始运行,并在排序时开始合并数组:
合并排序 1
3. 实现
对于实现,我们将编写一个 mergeSort 函数,该函数将输入数组及其长度作为参数。这将是一个递归函数,因此我们需要基础条件和递归条件。
基本条件检查数组长度是否为 1,它将返回。对于其余情况,将执行递归调用。
**对于递归情况,我们得到中间索引并创建两个临时数组 l[] 和 r[]。**然后,我们以递归方式为两个子数组调用 mergeSort 函数:
public static void mergeSort(int[] a, int n) {
if (n < 2) {
return;
}
int mid = n / 2;
int[] l = new int[mid];
int[] r = new int[n - mid];
for (int i = 0; i < mid; i++) {
l[i] = a[i];
}
for (int i = mid; i < n; i++) {
r[i - mid] = a[i];
}
mergeSort(l, mid);
mergeSort(r, n - mid);
merge(a, l, r, mid, n - mid);
}
接下来,我们调用 merge 函数,该函数接收输入和两个子数组,以及两个子数组的开始和结束索引。
merge 函数逐个比较两个子数组的元素,并将较小的元素放入输入数组中。
当我们到达其中一个子数组的末尾时,另一个数组中的其余元素被复制到输入数组中,从而为我们提供了最终排序的数组:
public static void merge(
int[] a, int[] l, int[] r, int left, int right) {
int i = 0, j = 0, k = 0;
while (i < left && j < right) {
if (l[i] <= r[j]) {
a[k++] = l[i++];
}
else {
a[k++] = r[j++];
}
}
while (i < left) {
a[k++] = l[i++];
}
while (j < right) {
a[k++] = r[j++];
}
}
该程序的单元测试为:
@Test
public void positiveTest() {
int[] actual = { 5, 1, 6, 2, 3, 4 };
int[] expected = { 1, 2, 3, 4, 5, 6 };
MergeSort.mergeSort(actual, actual.length);
assertArrayEquals(expected, actual);
}
4. 复杂性
由于合并排序是一种递归算法,因此时间复杂度可以表示为以下递归关系:
T(n) = 2T(n/2) + O(n)
2T(n/2)对应子数组排序所需的时间,O(n)是合并整个数组所需的时间。
求解后,时间复杂度将达到 O(nLogn)。
对于最坏、平均和最好的情况都是如此,因为它总是将数组一分为二,然后合并。
该算法的空间复杂度为 O(n),因为我们在每个递归调用中创建临时数组。
- 结论
在这篇简短的文章中,我们探讨了合并排序算法以及如何在 Java 中实现它。