三、归并排序
归并排序的基本思想:
将一个数组不断地折半划分,当划分的数组足够小的时候每个区段中只有一个元素,每次比较都会都会使子序列有序,最后合并成原始的有序数列。归并排序是稳定的排序算法。
具体的算法实现:
- MergeSort函数递归实现对原数组的折半划分
- _Merge函数实现对字序列的排序
- memcpy函数是c/c++的内存拷贝函数
函数原型
void *memcpy(void *destin, void *source, unsigned n);
参数
destin– 指向用于存储复制内容的目标数组,类型强制转换为 void 指针。
source– 指向要复制的数据源,类型强制转换为 void* 指针。
n– 要被复制的字节数。
功能
从源source所指的内存地址的起始位置开始拷贝n个字节到目标destin所指的内存地址的起始位置中。
归并排序的算法时间复杂度分析:
归并的时间复杂度分析:主要是考虑两个函数的时间花销,一、数组划分函数 MergeSort();二、有序数组归并函数_ Merge();
_Merge()函数的时间复杂度为O(n),因为代码中有2个长度为n的循环(非嵌套),所以时间复杂度则为O(n);
简单的分析下元素长度为n的归并排序所消耗的时间 T[n]:调用MergeSort()函数划分两部分,那每一小部分排序好所花时间则为 T[n/2],而最后把这两部分有序的数组合并成一个有序的数组_Merge()函数所花的时间为 O(n);
公式:T[n] = 2T[n/2] + O(n)=O(nlog(n));
#include <stdio.h>
#include <string.h>
//分组归并
void _Merge(int *a, int begin1, int end1, int begin2, int end2, int *tmp)
{
int index = begin1;
int i = begin1, j = begin2;
//注意:当划分的区间足够小时,begin1==end1,begin2==end2
while (i <= end1&&j <= end2){
if (a[i]<=a[j])
tmp[index++] = a[i++];
else
tmp[index++] = a[j++];
}
//将左边元素填充到tmp中
while (i <= end1)
tmp[index++] = a[i++];
//将右边元素填充的tmp中
while (j <= end2)
tmp[index++] = a[j++];
//将tmp中的数据拷贝到原数组对应的序列区间
memcpy(a + begin1, tmp + begin1, sizeof(int)*(end2 - begin1 + 1));
}
//归并排序
void MergeSort(int *a, int left, int right, int *tmp)
{
if (left >= right)
return;
//mid将数组二分
int mid = left + ((right - left) >> 1);
//左边归并排序,使得左子序列有序
MergeSort(a, left, mid, tmp);
//右边归并排序,使得右子序列有序
MergeSort(a, mid + 1, right, tmp);
//将两个有序子数组合并
_Merge(a, left, mid, mid + 1, right, tmp);
}
//打印数组
void PrintArray(int *a, int len)
{
for (int i = 0; i < len; i++)
printf("%d ", a[i]);
printf("\n");
}
int main()
{
int i,n;
scanf("%d",&n);
int a[n],tmp[n];
for(i=0;i<n;i++){
scanf("%d",&a[i]);
}
MergeSort(a,0,n-1,tmp);
PrintArray(a,n);
return 0;
}