归并排序(Merge Sort)是一种典型的分治思想的应用。它将一个待排序的序列分割成若干个子序列,每个子序列是一个有序的序列。然后再把有序子序列合并为整体有序序列。
以下是使用C++实现归并排序的示例代码:
cpp复制代码
#include <iostream> | |
#include <vector> | |
using namespace std; | |
// 合并两个有序数组 | |
void merge(vector<int>& arr, int left, int mid, int right) { | |
int i = left, j = mid + 1; | |
vector<int> temp(right - left + 1); // 临时数组 | |
int k = 0; | |
// 将较小的元素放入临时数组 | |
while (i <= mid && j <= right) { | |
if (arr[i] <= arr[j]) { | |
temp[k++] = arr[i++]; | |
} else { | |
temp[k++] = arr[j++]; | |
} | |
} | |
// 将剩余的元素放入临时数组 | |
while (i <= mid) { | |
temp[k++] = arr[i++]; | |
} | |
while (j <= right) { | |
temp[k++] = arr[j++]; | |
} | |
// 将临时数组中的元素复制回原数组 | |
for (i = left, k = 0; i <= right; ) { | |
arr[i++] = temp[k++]; | |
} | |
} | |
// 归并排序主函数 | |
void mergeSort(vector<int>& arr, int left, int right) { | |
if (left < right) { | |
int mid = left + (right - left) / 2; // 防止溢出 | |
mergeSort(arr, left, mid); // 对左半部分排序 | |
mergeSort(arr, mid + 1, right); // 对右半部分排序 | |
merge(arr, left, mid, right); // 合并两个有序数组 | |
} | |
} | |
int main() { | |
vector<int> arr = {38, 27, 43, 3, 9, 82, 10}; | |
int n = arr.size(); | |
mergeSort(arr, 0, n - 1); | |
// 输出排序后的结果 | |
for (int i = 0; i < n; i++) { | |
cout << arr[i] << " "; | |
} | |
cout << endl; | |
return 0; | |
} |
在这个程序中,mergeSort
函数是递归调用的,它将数组arr
分割成更小的部分,直到每个部分只包含一个元素(此时可以认为它是有序的)。然后,merge
函数负责将两个有序的子数组合并成一个有序数组。
merge
函数使用了临时数组temp
来存储合并过程中的元素。它比较两个子数组的当前元素,并将较小的元素放入临时数组,直到一个子数组的所有元素都被放入临时数组。然后,它将另一个子数组剩余的元素放入临时数组。最后,将临时数组中的元素复制回原数组。
在main
函数中,我们创建了一个待排序的数组arr
,然后调用mergeSort
函数对其进行排序,并输出排序后的结果。
归并排序的时间复杂度是O(n log n),其中n是待排序数组的长度。这是因为归并排序的递归调用树是平衡的,每一层处理的数据量是n,而递归的深度是log n。空间复杂度是O(n),因为需要用到一个临时数组来存储合并过程中的元素。如果采用原地归并排序(in-place merge sort),则可以在空间复杂度上做一些优化,但实现起来会更复杂。
归并排序的优点主要包括:
- 稳定性:归并排序是一种稳定的排序算法,即在排序过程中,相等的元素的相对顺序不会发生改变。
- 高效性:归并排序的时间复杂度为O(n log n),其中n是待排序数组的长度。这意味着无论输入数据的初始状态如何,归并排序都能保持相对高效的性能。
- 分治策略:归并排序采用了分治策略,将大问题分解为小问题,然后递归地解决这些小问题,最后合并结果。这种策略使得归并排序易于理解和实现。
然而,归并排序也存在一些缺点:
- 空间复杂度:归并排序的空间复杂度为O(n),需要额外的空间来存储临时数组。这可能导致在处理大数据集时,内存使用成为一个问题。尽管可以通过一些技巧(如原地归并排序)来减少空间复杂度,但这些技巧通常会增加实现的复杂性。
- 不适合小数据集:对于非常小的数据集,归并排序可能不是最优的选择。因为递归调用和合并操作可能会引入额外的开销,使得它在小数据集上的性能不如一些简单的排序算法(如插入排序或选择排序)。
总的来说,归并排序是一种高效且稳定的排序算法,适用于处理大规模数据集。然而,在处理小数据集或需要严格控制内存使用的情况下,可能需要考虑其他排序算法。