一、归并排序
1、基本思想
归并排序(Merge sort,台湾译作:合并排序)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
算法原理:
1>按照类似快速排序的方法递归地将待排序序列依次划分为两个区间,区间只剩一个数停止划分;2>如果一个区间只剩一个数,我们可将其看做有序区间,然后对左右两个小区间进行归并,归并后仍要保持区间的有序性;
3>同2>提到的方法我们每次将两个有序的子区间归并为一个大的有序区间,并返回给上一层递归;
4>直到所有划分的区间归并为一个有序序列,归并排序就算完成。
算法图解(假设升序):
2、算法执行步骤
1》申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
2》设定两个指针,最初位置分别为两个已经排序序列的起始位置
3》比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
4》重复步骤3直到某一指针达到序列尾
5》将另一序列剩下的所有元素直接复制到合并序列尾
3、排序效果图
4、时间复杂度&&空间复杂度
归并排序,它采取分而治之(Divide-and-Conquer)的策略。归并排序的步骤如下:
<1> Divide: 把长度为n的输入序列分成两个长度为n/2的子序列。
<2> Conquer: 对这两个子序列分别采用归并排序。
<3> Combine: 将两个排序好的子序列合并成一个最终的排序序列。
比较操作的次数介于和
。 赋值操作的次数是
。
归并算法的空间复杂度为:O(n*lgn).
5、代码实现
//递归实现归并排序
#pragma once
#include <iostream>
#include <assert.h>
using namespace std;
void Merge(int* a,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 (a[begin1] <= a[begin2])
{
tmp[index++] = a[begin1++];
}
else
{
tmp[index++] = a[begin2++];
}
}
//如果左区间还有数据,直接放到中间数组后边
while(begin1 <= end1)
{
tmp[index++] = a[begin1++];
}
//如果右区间还有数据,直接放到中间数组后边
while(begin2 <= end2)
{
tmp[index++] = a[begin2++];
}
//将中间数组的值考回原数组
memcpy(a,tmp,index*sizeof(int));
/*for (int i = left; i < index; ++i)
{
a[i] = tmp[i];
}*/
}
void _MerSort(int* a,int* tmp,int left,int right)
{
//当区间只有一个数或没有数据时递归返回
if (left >= right)
return;
int mid = left + ((right - left)>>1);//划分左右区间的中间值
_MerSort(a,tmp,left,mid); //递归左边区间,使之有序
_MerSort(a,tmp,mid+1,right);//递归右边区间,使之有序
Merge(a,tmp,left,mid,right);//对左右两个有序区间进行归并
}
void MergeSort(int* a,size_t n)//归并排序
{
assert(a);
int* tmp = new int[n];//中间数组
_MerSort(a,tmp,0,n-1);
delete[]tmp;
}
void PrintArray(int* a,size_t n)
{
for (size_t i = 0; i < n; ++i)
{
cout<<a[i]<<" ";
}
cout<<endl;
}
void TestMergeSort()
{
int a[] = {2,5,4,9,3,6,8,7,1,0};
size_t sz = sizeof(a)/sizeof(a[0]);
MergeSort(a,sz);
PrintArray(a,sz);
}
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;
}
运行结果:
二、各种排序的比较