归并排序算法完全遵循分治模式。直观上其操作如下:
- 分解:分解待排序的n个元素的序列成各具n/2个元素的两个子序列。
- 解决:使用归并排序递归地排序两个子序列。
- 合并:合并两个已排序的子序列以产生已排序的答案。
我们直接来看例子理解算法的过程,下面是要排序的数组,总共8个元素,我们划分为左右两个数组L和R(L和R都已经是有序的),L是原数组左边4个元素,R是原数组右边4个元素,为了让排序终止,两个数组的末尾加了一个无穷,用k指针指向原数组第一个元素2,i指针指向L数组第一个元素2,j指针指向R数组第一个元素1:
比较i指针所指2和j指针所指1:j指针所指1更小,k指针对应第一个元素赋值为1,j和k指针右移。
比较i指针所指2和j指针所指2:一样大,k指针对应第2个元素赋值为2,i和k指针右移。
比较i指针所指4和j指针所指2:j指针所指2更小,k指针对应第3个元素赋值为2,j和k指针右移。
如此做下去,直到i和j指针都遍历到最后:
对于上面的逻辑我们可以写作一个函数叫merge,它的目的是合并两个有序数组为一个新的有序数组,它的伪代码是:
其中A是一个数组,p、q和r是数组下标,满足p≤q<r。该过程假设子数组A[p.q]和A[q+1,r]都已排好序。它合并这两个子数组形成单一的已排好序的子数组并代替当前的子数组A[p.r]。
用C++实现一下:
void merge(std::vector<int>& A, int p, int q, int r)
{
int n1 = q - p + 1;
int n2 = r - q;
std::vector<int> L(n1, 0);//[p,q]
std::vector<int> R(n2, 0);//[q+1,r]
for (int i = 0; i < n1; ++i)
L[i] = A[p + i];
for (int i = 0; i < n2; ++i)
R[i] = A[q + i - 1];
int i = 0;
int j = 0;
for (int k = p; k <= r; ++k)
{
if (i == n1)
{
A[k] = R[j];
j++;
}
else if (j == n2)
{
A[k] = L[i];
i++;
}
else if (L[i] <= R[j])
{
A[k] = L[i];
i++;
}
else
{
A[k] = R[j];
j++;
}
}
}
这样我们可以得到自底向上的排序:
算法的伪代码是:
void mergeSort(std::vector<int> &A, int p, int r)
{
if (p < r)
{
int q = (p + r) / 2;
mergeSort(A, p, q);
mergeSort(A, q + 1, r);
merge(A, p, q, r);
}
}
测试代码:
int main()
{
std::vector<int> A({
1, 3