归并排序
1.基本思想:
将待排序的元素分为两个长度相等的子序列,为每一个子序列排序,然后将他们合并成一个序列。合并两个子序列的过程叫做两路归并。
2.具体步骤:
(1)按照类似于快速排序的道理,我们把待排序区间划分成两个长度想等的子区间。
(2)递归其子区间,直到区间里面的元素只剩下一个,我们认为这个子区间已经有序。
(3)当区间只剩下一个元素时候,每次将相邻两个区间的成一个大的有序的区间,然后一层层往上返回。
(4)直到返回到第一层,整个区间已经有序。
3.思想流图:
4.合并步骤:
(1)在合并的时候,首先申请空间,空间大小为合并两区间大小之和。
(2)定义两个指针分别指向两个合并元素的第一个元素。
(3)比较两个指针指向元素大小,将较小的放入新空间,较小的指针向后走。
(4)当一个指针走到边界的时候,另一个指针将剩余元素放到新空间。
(5)新空间元素满的时候,停止,合并完成。
5.实现代码:
void MergeSort(int *array, int size)
{
assert(array);
int *tmp = new int[size];
_merge(array, tmp, 0, size - 1);
delete[] tmp;
}
void _merge(int *array, int *tmp, int left, int right)
{
if (left >= right)
return;
int mid = left + ((right - left) >> 1);
_merge(array, tmp, left, mid);//递归划分左区间
_merge(array, tmp, mid + 1, right);//递归划分右区间
Merge(array, tmp, left, mid, right);//合并
}
void Merge(int *array, int *tmp, int left, int mid,int right)
{
int begin1 = left;
int end1 = mid;
int begin2 = mid + 1;
int end2 = right;
int index = left;
while (begin1 <= end1&&begin2 <= end2)
{
if (array[begin1] < array[begin2])
{
tmp[index++] = array[begin1++];
}
else
{
tmp[index++] = array[begin2++];
}
}
while (begin1 <=end1)
{
tmp[index++] = array[begin1++];
}
while (begin2 <=end2)
{
tmp[index++] = array[begin2++];
}
memcpy(array, tmp, sizeof(int)*index);
}
6.非递归方式
当然我们也可以直接忽略递归划分区间的过程,从一开始就直接进行区间的归并,一样可以实现归并排序。
void Merge_sort(int *a, int length)
{
int i, begin1, end1, begin2, end2, index;
int *tmp = new int[length];
for (i = 1; i < length; i *= 2)
{
for (begin1 = 0; begin1 < length - i; begin1 = end2)
{
begin2 = end1 = begin1 + i;
end2 = end1 + i;
if (end2 > length)
end2 = length;
index = 0;
while (begin1 < end1 && begin2 < end2)
tmp[index++] = a[begin1] > a[begin2] ? a[begin2++] : a[begin1++];
while (begin1 < end1)
a[--begin2] = a[--end1];
while (index > 0)
a[--begin2] = tmp[--index];
}
}
delete []tmp;
}
7.排序性能
时间复杂度:归并排序最好,最差,平均的时间复杂度为O(NlogN);
空间复杂度:O(N);
稳定性:稳定。