插入排序与归并排序算法比较
实验内容:
1、 编写函数分别实现插入排序和归并排序算法
2、 编写主函数通过调用函数实现对待排数据的调用
3、 待排数据利用随机函数循环产生10万个以上的数据
4、 利用求系统时间的函数,分别求出2个排序函数调用前和调用后的时间,计算出插入排序运行时间和归并排序的运行时间
5、 算法的比较:
(1) 相同待排序数据下,插入排序和归并排序算法的运行时间比较;
(2) 同一种排序算法下最好的情况,一般情况,最坏的情况运行时间比较
函数分析:
(1) 插入排序
基本思想:将一个数插入有序数列,插入后仍然有序。
设计原理:1.给出一个无序数列,先取出一个数(一个数自然是一个有序数列);
2.再取下一个数,往之前取出的数进行排序,直到找到合适的位置为止(需要一层内循环);
3.继续按第二步操作,直到取到数列最后一位为止(进行一层外循环);
时间复杂度:O(n^2)
代码:
void insert(int n,int a[]){
int j,i,key;
for(i=1;i<n;i++){ //外层循环
key=a[i];
j=i-1;
while(j>=0&&a[i]<a[j]){ //内层循环
a[j+1]=a[j];
j--;
}
a[j+1]=key;
}
}
(2) 归并排序
递归:不撞南墙不回头。(自己理解)
基本思想:将无序序列分成大致相等的两部分。再对两部分进行递归排序,再将两个有序部分并归成一个有序序列。
设计原理:(分治策略)
分解+合并(两个函数)
1. 将一个大序列的排序问题分解为对两个或多个子序列的排序问题
2. 然后对子序列递归使用同样的方发进行排序
3. 在子序列排好后,将结果合并起来
时间复杂度:O(nlogn)
代码:
编写合并函数void merge(int ,int ,int ,int,),易陷的误区。
1. 容易新建数组C的计数值i设为0,如果放在函数内,将犯一个大错误。如果做全局变量也不太方便。最好是将start赋值给i,因为每次函数时给从start到end之间的数进行排序,所以在函数内给i赋值start是最清晰的。
2. 注意数组a,应该清楚的知道是给数组a排序,目标是在数组a的基础上排序。所以应该将每次排好序赋给数组c的值在重新赋给数组a,否则将起不到在每次分解后再合并的作用,最后结果只是给n/2的两半无序部分排序。结果错误。
3. 合并设计思路:一:在两半部分都存在数的时候,比较大小,小的先赋值给数组c;重复操做;
直到其中一部分为空。
二:如果有一部分为空,将其余有序数组直接插到c数组后面。
void merge(int a[],int start,int mid,intend){//合并
intj,k,p;
j=start;k=mid+1;
p=start;
while(p<=end){
if((j<=mid)&&(k<=end))
{
if(a[j]<a[k])
{
c[p]=a[j];j++;
p++;
}
else
{
c[p]=a[k];k++;
p++;
}
}
elseif(j>mid)
{
for(;k<=end;k++)
{
c[p]=a[k];
p++;
}
}
elseif(k>end)
for(;j<=mid;j++)
{
c[p]=a[j];
p++;
}
}
for(inti=start;i<=end;i++)
a[i]=c[i];
}
分解函数void merge_sort(int ,int ,int,)中的难题;了解到递归函数的两次调用递归的过程,抽象的去理解;这样会更好的理解下面的代码;
void merge_sort(int a[],int start,intend){ //分治法
intmid;
mid=(start+end)/2;
if(end>start){
merge_sort(a,start,mid);
merge_sort(a,mid+1,end);
merge(a,start,mid,end);
}
else
return;
}
(3)rand()与srand()
rand()是随机数发生器,所在头文件:stdlib.h,用法:int rand(void);
函数说明:
rand()的内部实现是用线性同余法做的,它不是真的随机数,因为周期特别长,所以在一定的范围内可以看成随机的。
rand()返回一随机数值的范围在0至rand_max之间。0~rand_max每个数字被选中的几率是相同的。
用户未设定随机数种子,系统默认的随机数种子为1.
rand()产生的是伪随机数字,每次执行时相同;若要不同,用srand()初始化它。
srand()是初始化随机数的发生器;所在头文件stdlib.h;用法:void srand(unsigned int seed);
函数说明:
srand()用来你设置rand()产生随机数时的随机数种子 ;
参数seed必须是个整数,通常可以利用time(0)
返回值或NULL来当做seed;用time函数值(即当前时间),因为两次调用rand的时间通常是不同的,这样就可以保证种子的随机性。
如果每次seed都设相同值,rand()所产生的随机数
值每次就会一样。
rand()与srand()关系
rand()和srand()要一起使用,其中srand()用来初始
化随机数种子,rand()用来产生随机数。
算法的对比:
归并排序的时间复杂度:nlogn;
插入排序的时间复杂度:n^2;
程序:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int c[100001]={0};
int s[100001]={0},s1[100001]={0};
void insort(int n,int b[])
{
int j,i,key;
for(i=1;i<n;i++)//外层循环
{
key=b[i];
j=i-1;
while(j>=0&&key<b[j])//内层循环
{
b[j+1]=b[j];
j--;
}
b[j+1]=key;
}
}
void merge(int a[],int start,int mid,int end){
int j,k,p;
j=start;k=mid+1;
p=start;
while(p<=end){
if((j<=mid)&&(k<=end))
{
if(a[j]<a[k])
{
c[p]=a[j];j++;
p++;
}
else
{
c[p]=a[k];k++;
p++;
}
}
elseif(j>mid)
{
for(;k<=end;k++)
{
c[p]=a[k];
p++;
}
}
elseif(k>end)
for(;j<=mid;j++)
{
c[p]=a[j];
p++;
}
}
for(inti=start;i<=end;i++)
a[i]=c[i];
}
void merge_sort(int a[],int start,int end){ //分治法
int mid;
mid=(start+end)/2;
if(end>start){
merge_sort(a,start,mid);
merge_sort(a,mid+1,end);
merge(a,start,mid,end);
}
else
return;
}
int main(){
inti,n,n1,a[100001]={0},b[100001]={0};
double t;
time_tc_beg,c_end,end;
printf("输入要排的个数:\n");
scanf("%d",&n);
n1=n-1;
srand((unsigned)time(NULL)); //产生随机种子
for(i=0;i<n;i++) //产生随机数
{
a[i]=rand()%1000000;
b[i]=a[i];
printf("%d ",a[i]);
}
printf("\n\n");
c_beg=clock();
merge_sort(a,0,n-1);
c_end=clock();
t=(double)(c_end-c_beg)*1000/CLOCKS_PER_SEC;
printf("\n一般情况\n");
printf("归并排序所花费的时间:%f 毫秒\n",t);
insort(n,b);
end=clock();
t=(double)(end-c_end)*1000/CLOCKS_PER_SEC;
printf("插入排序花费的时间:%f 毫秒\n",t);
printf("\n最好情况\n");
c_beg=clock();
merge_sort(a,0,n-1);
c_end=clock();
t=(double)(c_end-c_beg)*1000/CLOCKS_PER_SEC;
printf("归并排序所花费的时间:%f 毫秒\n",t);
insort(n,b);
end=clock();
t=(double)(end-c_end)*1000/CLOCKS_PER_SEC;
printf("插入排序花费的时间:%f 毫秒\n",t);
printf("%d\n",n);
printf("\n最坏情况\n");
for(i=0;i<n;i++)
{
s[i]=a[n1];
s1[i]=a[n1--];
}
c_beg=clock();
merge_sort(s,0,n-1);
c_end=clock();
t=(double)(c_end-c_beg)*1000/CLOCKS_PER_SEC;
printf("归并排序所花费的时间:%f 毫秒\n",t);
insort(n,s1);
end=clock();
t=(double)(end-c_end)*1000/CLOCKS_PER_SEC;
printf("插入排序花费的时间:%f 毫秒\n",t);
return 0;
}