归并(合并)排序(Merge Sort)
- 基于分治策略。
- 核心思想:就是把数组分成大小大致相同的两个子集合,分别对两个子集合进行排序,最终将排序好的子集合合并。
递归法
// 归并排序递归框架
int tmpArray[];
void MergeSort(int array[], int left, int right)
{
if (left < right) // 至少两个元素
{
int i = (left + right) / 2; // 取中点
MergeSort(array, left, i);
MergeSort(array, i + 1, right);
Merge(array, tmpArray, left, i, right); // 合并到数组tmpArray
Copy(array, tmpArray, left, right); // 将tmpArray中的数据复制回array
}
}
其中,算法 Merge
合并两个排好序的数组到一个新的数组 tmpArray 中,然后由 Copy
将合并后的数组再复制回 array 中。 Merge
和 Copy
操作都是在
O
(
n
)
O(n)
O(n) 时间内完成的,因此归并排序算法对
n
n
n 个元素排序的时间复杂度为:
T
(
n
)
=
{
O
(
1
)
n
⩽
1
2
T
(
n
/
2
)
+
O
(
n
)
n
>
1
T(n)=\left\{\begin{array}{ll} O(1) & n \leqslant 1 \\ 2T(n/2)+O(n) & n>1 \end{array}\right.
T(n)={O(1)2T(n/2)+O(n)n⩽1n>1
解得:
T
(
n
)
=
O
(
n
log
n
)
T(n)=O(n\log n)
T(n)=O(nlogn)
非递归法
int *MergeSort(int array[], int len)
{
int *a = array;
int *b = new int[len];
// 每次循环的规模(seg)翻倍
for (int seg = 1; seg < len; seg += seg)
{
for (int start = 0; start < len; start += seg + seg)
{
int low = start, mid = min(start + seg, len), high = min(start + seg + seg, len);
int k = low;
int start1 = low, end1 = mid;
int start2 = mid, end2 = high;
while (start1 < end1 && start2 < end2) // 合并两个数组
b[k++] = a[start1] < a[start2] ? a[start1++] : a[start2++];
while (start1 < end1) // 数组2已经合并完了,开始合并剩余的数组1
b[k++] = a[start1++];
while (start2 < end2) // 数组1已经合并完了,开始合并剩余的数组2
b[k++] = a[start2++];
}
int *temp = a;
a = b;
b = temp;
}
if (a != array)
{
for (int i = 0; i < len; i++)
b[i] = a[i];
b = a;
}
return b;
}
使用循环的方法,就是先将待排序数组中的相邻元素两两配对,然后按照大小进行两两合并,每次合并的规模增加一倍。
如果想了解其他排序算法可见:算法分析与设计:7大排序算法大汇总(C++)