4-5 比较排序:归并排序
归并排序
归并排序是一种流行的排序算法,以其高效性和稳定性而闻名。它遵循分治法。其工作原理是递归地将输入数组分成两半,递归地对这两半进行排序,最后将它们合并在一起,从而得到排序后的数组。

以下是归并排序工作原理的详细步骤说明:
- 分割:递归地将列表或数组分割成两半,直到无法再分割为止。
- 征服:使用归并排序算法对每个子数组进行单独排序。
- 合并:将已排序的子数组按排序顺序重新合并。此过程持续进行,直到两个子数组中的所有元素都合并完毕。
代码实现
#include <iostream>
#include <vector>
// Merges two subarrays of arr[].
// First subarray is arr[left..mid]
// Second subarray is arr[mid+1..right]
void merge(std::vector<int>& arr, int left, int mid, int right)
{
int n1 = mid - left + 1;
int n2 = right - mid;
// Create temp vectors
std::vector<int> L(n1), R(n2);
// Copy data to temp vectors L[] and R[]
for (int i = 0; i < n1; i++)
{
L[i] = arr[left + i];
}
for (int j = 0; j < n2; j++)
{
R[j] = arr[mid + 1 + j];
}
int i = 0, j = 0;
int k = left;
// Merge the temp vectors back
// into arr[left..right]
while (i < n1 && j < n2)
{
if (L[i] <= R[j])
{
arr[k] = L[i];
i++;
}
else
{
arr[k] = R[j];
j++;
}
k++;
}
// Copy the remaining elements of L[],
// if there are any
while (i < n1)
{
arr[k] = L[i];
i++;
k++;
}
// Copy the remaining elements of R[],
// if there are any
while (j < n2)
{
arr[k] = R[j];
j++;
k++;
}
}
// begin is for left index and end is right index
// of the sub-array of arr to be sorted
void mergeSort(std::vector<int>& arr, int left, int right)
{
if (left >= right)
{
return;
}
int mid = left + (right - left) / 2;
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
merge(arr, left, mid, right);
}
// Driver code
int main()
{
std::vector<int> arr = {38, 27, 43, 10};
int n = arr.size();
mergeSort(arr, 0, n - 1);
for (int i = 0; i < arr.size(); i++)
{
std::cout << arr[i] << " ";
}
std::cout << std::endl;
return 0;
}
输出:

归并排序的递推关系、复杂度分析、优缺点、以及应用
归并排序的递推关系为:
{ Θ(1) , if n = 1
T(n) = {
{ 2T(n/2) + Θ(n) , if n > 1
- T(n) 表示算法对大小为 n 的数组进行排序所需的总时间。
- 2T(n/2) 表示算法递归排序数组两部分所需的时间。由于每部分都有 n/2 个元素,因此需要两次递归调用,每次调用的输入大小为 (n/2)。
- O(n) 表示合并两个已排序部分所需的时间。
归并排序的复杂度分析
时间复杂度:
- 最佳情况: O(n log n),当数组已经排序或接近排序时。
- 平均情况: O(n log n),当数组随机排序时。
- 最坏情况: O(n log n),当数组按逆序排序时。
辅助空间: O(n),合并过程中使用的临时数组需要额外的空间。
归并排序的优点
- 稳定性:归并排序是一种稳定的排序算法,这意味着它可以保持输入数组中相等元素的相对顺序。
- 保证最坏情况下的性能:归并排序的最坏情况时间复杂度为O(N logN),这意味着即使在大型数据集上也能表现良好。
- 易于实施:分而治之的方法简单明了。
- 自然并行:我们独立合并子数组,使其适合并行处理。
归并排序的缺点
- 空间复杂度:归并排序需要在排序过程中使用额外的内存来存储合并后的子数组。
- 非原地排序:归并排序不是一种原地排序算法,这意味着它需要额外的内存来存储排序后的数据。这在内存使用受限的应用中可能是一个缺点。
- 一般来说,归并排序比快速排序慢,因为快速排序对缓存更友好,因为它直接在内存中运行。
归并排序的应用:
- 对大型数据集进行排序
- 外部排序(当数据集太大而无法放入内存时)
- 用于解决诸如倒数计数、右侧较小计数和超过计数等问题
- 归并排序及其变体被广泛应用于编程语言的库方法中。其变体TimSort则被 Python、Java、Android 和 Swift 所采用。归并排序之所以更受青睐,用于对非原始类型进行排序,主要原因在于其稳定性,而快速排序则不具备这种稳定性。Java 中的
Arrays.sort方法使用快速排序,而Collections.sort方法则使用归并排序。 - 它是链表排序的首选算法。
- 由于我们可以独立地对子数组进行排序,然后再合并,因此很容易实现并行化。
- 归并排序的 merge 函数可以高效地解决两个已排序数组的并集和交集等问题。

浙公网安备 33010602011771号