基本思想
归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略。
分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之。
动画演示
C++代码
//治阶段:排序并合并分阶段拆分的序列
void merge(vector<int>& v1, vector<int>& v2, int left, int mid, int right)
{
int i = left; //左序列起始位置
int j = mid + 1; //右序列起始位置
int begin = left; //排序数组的起始位置
//当前分阶段序列排序放入排序后数组v2
while (i <= mid && j <= right)
{
if (v1[i] <= v1[j])
{
v2[begin++] = v1[i++];
}
else
{
v2[begin++] = v1[j++];
}
}
//当前分阶段左右序列长度不等的情况
//左序列长,则上面循环过后i还小于等于mid, 则将左序列剩余元素移至排序数组后面
//因为左序列有序且上面已和右序列排序,所以左序列剩余的元素一定大于右序列的,因此可以直接移至排序数组
while (i <= mid)
{
v2[begin++] = v1[i++];
}
//右序列长,同理
while (j <= right)
{
v2[begin++] = v1[j++];
}
//将当前分阶段的区间的排序后的序列放入原数组
for (int t = left; t <= right; t++)
{
v1[t] = v2[t];
}
}
//v1:给定待排序数组
//v2:存放排序后序列的数组
//left:指定v1的左边界
//right:指定v1的右边界
void mergeSort(vector<int>& v1, vector<int>& v2, int left, int right)
{
if (left < right) //递归终止条件
{
int mid = left + (right - left) / 2; //+left 是为了防止溢出
//分阶段:将[left, right]区间的序列等分成左右两个子序列,直至left == right为止,即拆分到左右序列均只有一个元素为止。
mergeSort(v1, v2, left, mid);
mergeSort(v1, v2, mid + 1, right);
//治阶段
merge(v1, v2, left, mid, right);
}
}
时间复杂度
假设待排序的数组元素个数为n,设高度为x,x意味着该数组中的n个元素需要连续二分x次才剩下1个元素,即n/2^x=1,x=log2n,每一层的总比较次数为n,所以时间复杂度为O(nlogn)。
空间复杂度
归并的空间复杂度就是那个临时的数组(我们通过参数传递来取代了临时创建,相当于每次递归调用时将数组大小n也压入栈中了)和递归时压入栈的数据占用的空间:n + logn,所以空间复杂度为: O(n)。
算法稳定性
因为交换元素时,可以在相等的情况下做出不移动的限制,所以归并排序是稳定的;