归并排序
思想:
1、先对数据的整体进行划分:把数据划分为左右均等的两部分,继续划分,直到数据分组有序为止;
1、先对数据的整体进行划分:把数据划分为左右均等的两部分,继续划分,直到数据分组有序为止;
![](https://i-blog.csdnimg.cn/blog_migrate/19b2d057d0218cbf3544bc7ff1095a40.png)
2、每个分组只剩下一个元素则是有序的
3、把两个部分(数据)归并成一个部分:逐次归并:给定一个辅助空间,给定一个指针放在第一个数组的起始位置x1,给定另一个指针放在另一个数组的起始位置x2,给定第三个指针放在辅助空间的位置x3比较x1和x2,将较小的元素搬移到辅助空间中,把刚刚较小的那个元素的指针向该数组的下一个位置移动。x3向后走一步,继续比较x1和x2,并搬移元素。
![](https://i-blog.csdnimg.cn/blog_migrate/388580c2a2915d30ad9cdee8e9b82b79.png)
实现代码
//合并需要给定两个数组的空间及辅助空间
void MergeData(int *array, int left, int mid,int right,int *tmp)
{
//计算出空间的范围
int beginL = left;//左边的左边界
int endL= mid;//左边的右边界
int beginR = mid;//右边的左边界
int endR = right;//右边的右边界
int index = left;//临时空间的起始位置
while (beginL < endL&&beginR < endR)//左边界中有数据,右边界中有数据
{
if (array[beginL] < array[beginR])
//搬到辅助空间里去
tmp[index++] = array[beginL++];
else
tmp[index++] = array[beginR++];
}
//左边的数据没有搬移完
while (beginL < endL)
{
tmp[index++] = array[beginL++];
}
//右边的数据没有搬移完
while (beginR < endR)
{
tmp[index++] = array[beginR++];
}
}
void _MergeSort(int *array, int left, int right, int *tmp)
{
if (right-left>1)//只剩下一个元素则不进行划分
{
int mid = left + ((right - left) >> 1);
//递归进行划分
//排左边
_MergeSort(array, left, mid, tmp);
//排右边
_MergeSort(array, mid, right, tmp);
//将两个分组归并成一个分组,放入临时空间里
MergeData(array, left, mid, right, tmp);
//把临时空间里面的数据拷贝至待排序的空间中去
memcpy(array + left, tmp + left, sizeof(array[0])*(right - left));
}
}
void MergeSort(int *array, int size)
{
//申请辅助空间
int *tmp = (int *)malloc(size*sizeof(array[0]));
if (NULL == tmp)
{
assert(0);
return;
}
//排序
_MergeSort(array, 0, size,tmp);
//释放空间
free(tmp);
}
时间复杂度:每层需要O(n),平衡树,深度为lgN所以时间复杂度为O(nlgN);没有最好和最差的场景
空间复杂度:O(n):借助了一个辅助空间
稳定性:稳定的,相邻元素归并在一起,不可能出现跨区间交换……
适用于:数据量比较大,一次加载不了的数据(外部排序)
4、非递归的方式实现(也需要辅助空间)
![](https://i-blog.csdnimg.cn/blog_migrate/89bb7c91e28ccab49cdad7e8d900a8e1.png)
//合并需要给定两个数组的空间及辅助空间
void MergeData(int *array, int left, int mid, int right, int *tmp)
{
//计算出空间的范围
int beginL = left;//左边的左边界
int endL = mid;//左边的右边界
int beginR = mid;//右边的左边界
int endR = right;//右边的右边界
int index = left;//临时空间的起始位置
while (beginL < endL&&beginR < endR)//左边界中有数据,右边界中有数据
{
if (array[beginL] < array[beginR])
//搬到辅助空间里去
tmp[index++] = array[beginL++];
else
tmp[index++] = array[beginR++];
}
//左边的数据没有搬移完
while (beginL < endL)
{
tmp[index++] = array[beginL++];
}
//右边的数据没有搬移完
while (beginR < endR)
{
tmp[index++] = array[beginR++];
}
}
void MergeSortNor(int *array, int size)
{
int gap = 1;
int i = 0;
//申请辅助空间
int *tmp = (int *)malloc(size*sizeof(array[0]));
if (NULL == tmp)
{
assert(0);
return;
}
while (gap<size)//gap==size为一个分组,也不用处理
{
for (i = 0; i < size; i += 2 * gap)//i+=2*gap:第一次归并第0个和第1个,第二次归并第2个和第三个……两两归并
{
//计算区间
int left = i;
int mid = left + gap;
int right = mid + gap;
//归并
if (mid > size)//防止mid越界
mid = size;
if (right > size)//防止right越界
right = size;
MergeData(array, left, mid, right, tmp);
}
//将元素拷回去
memcpy(array, tmp, size*sizeof(array[0]));
//归并下一次的数据
gap *= 2;
}
free(tmp);
}