}
//randomarray
voidRandomArray(inta[],intsize)//随机生成数组含n个元素,其元素各不相同
{
srand(time(NULL));
for(inti=0;ifor(inti=1;i<=size;i++)
{
intp=rand()%size;
while(a[p]!
=0){p=(++p)%size;}
a[p]=i;
}
show_array(a,size);
}
//copyarray
voidCopyArray(inta[],intb[],intsize)
{
for(inti=0;i}
intmain()
{
int*a;int*temp_a;
intsize=4;
cin>>size;
a=newint[size];
temp_a=newint[size];
RandomArray(temp_a,size);
CopyArray(temp_a,a,size);
show_array(a,size);
InsertSort(a,size);
show_array(a,size);
cout<<"插入排序比较次数为"<cout<<"插入排序移动次数为"<cout<<"总规模为"<clear_count();
CopyArray(temp_a,a,size);
show_array(a,size);
MergeSort(a,0,size-1,size);
show_array(a,size);
cout<<"合并排序比较次数为"<cout<<"合并排序移动次数为"<cout<<"总规模为"<clear_count();
CopyArray(temp_a,a,size);
show_array(a,size);
QuickSort(a,0,size-1);
show_array(a,size);
cout<<"快速排序比较次数为"<cout<<"快速排序移动次数为"<cout<<"总规模为"<show_array(a,size);
system("pause");
return0;
}}
1.3运行示例
1.4数据分析
(单次录入数据具有较大随机误差,只看增长趋势)
问题规模(n)
排序总复杂度规模(T(n))
插入排序
合并排序
快速排序
10
57
105
50
20
221
280
122
30
367
461
238
40
946
660
371
50
1394
879
432
80
3261
1570
856
100
4694
2064
1064
200
22912
4718
2447
500
130133
13668
7368
1000
504254
30309
17003
10000
43898103
401968
225489
根据列表分析,插入算法平均复杂度为
合并算法平均复杂度为
快速排序算法平均复杂度为
但是排序算法最坏情况下复杂度仍为
,为了验证这一点,取n=1000的已排好数组,快排总规模变为503497,取n=10000的已排好数组,快排总规模变为50034997。
说明快排算法对已经基本排好的数组反而耗时间更多。
2循环赛问题
2.1问题描述
设有n个运动员要进行网球循环赛。
设计一个满足下列条件的比赛日程表:
每个选手必须与其他n-1个选手各赛一次;
每个选手一天只能赛一次;
当n是偶数时,循环赛进行n-1天。
当n是奇数时,循环赛进行n天。
2.2问题分析
当n=(k=1、2、3、4,……,n=2、4、8、16,……)时,此时问题比较简单。
按照分治的策略,可将所有参赛的选手分为两部分,n=个选手的比赛日程表就可以通过为n/2=个选手设计的比赛日程表来决定。
递归地执行这种分割,直到只剩下2个选手时,比赛日程表的制定就变得很简单:
只要让这2个选手进行比赛就可以了。
再逐步合并子问题的解即可得到原问题的解。
推广当n为任意整数时:
当n小于或等于1时,没有比赛。
当n是偶数时,至少举行n-1轮比赛.
当n是奇数时,至少举行n轮比赛,这时每轮将会有一支球队轮空。
因此应对策略如下:
(1)当n/2为偶数时,与n=情形类似,可用分治法求解。
(2)当n/2为奇数时,递归返回的轮空的比赛要作进一步处理。
可以在前n/2轮比赛中让轮空选手与下一个未参赛选手进行比赛。
2.3源程序
#include
usingnamespacestd;
inta[100][100];
intb[100];
boolodd(intn)//判断n奇偶性
{
returnn&1;//n为奇数,返回1,n为偶数,返回0
}
voidcopyodd(intn)//n/2为奇数时的合并算法
{
intm=n/2;
for(inti=0;i{
b[i]=m+i;
b[m+i]=b[i];
}
for(inti=0;i{
//由左上角小块的值算出相应的左下角小块的值
for(intj=0;j{
if(a[i][j]>=m)
{
a[i][j]=b[i];
a[m+i][j]=(b[i]+m)%n;
}
elsea[m+i][j]=a[i][j]+m;
}
//由左上角小块的值算出相应的右上角和右下角小块的值
for(intj=1;j{
a[i][m+j]=b[i+j];
a[b[i+j]][m+j]=i;
}
}
}
voidcopy(intn)
{
intm=n/2;
for(inti=0;ifor(intj=0;j{
//由左上角小块的值算出对应的右上角小块的值
a[i][j+m]=a[i][j]+m;
//由右上角小块的值算出对应的左下角小块的值
a[i+m][j]=a[i][j+m];
//由左上角小块的值算出对应的右下角小块的值
a[i+m][j+m]=a[i][j];
}
}
voidmakecopy(intn)//合并算法
{
if((n/2)>1&&odd(n/2))copyodd(n);//n/2为奇数时
elsecopy(n);
}
voidtourna(intn)//改进的分治赛算法
{
if(n==1){a[0][0]=0;return;}
if(odd(n)){tourna(n+1);return;}//n为奇数,分治
tourna(n/2);//n为偶数,分治
makecopy(n);//合并
}
intmain()
{
intn;
cout<<"请输入参数队数:
"<cin>>n;
tourna(n);
cout<<"参数日程表为:
"<for(inti=0;ifor(intj=0;jcout<cout<}
system("pause");
return0;
}
2.4运行示例
3最大最小值问题
3.1问题描述与分析
在含有n个不同元素的集合中同时找出它的最大和最小元素
算法思想:
先相邻两个两个比较,较大的放入数组max[],较小的放入数组min[],然后从max[]数组求出最大,min[]数组求出最小即可。
从算法描述中可以看出,占据算法的主要执行次数的是比较过程,因此算法的复杂性主要跟比较次数相关
当n是2的幂时,即对于某个正整数k,n=
有
T(n)=2T(n/2)+2
=2(2T(n/4)+2)+2
=2*2T(n/4)+2*2+2
…..
=
+
-2
=3n/2-2
这是最优情况,平均则比直接比较少25%
3.2源程序
//findmaxandmin
#include
usingnamespacestd;
voidMax_Min(inta[],intn)
{
intm=(n+1)/2;
intmax[m];
intmin[m];
intk=0,j=0;
if(n/2!
=0)max[m-1]=min[m-1]=a[n-1];
for(inti=0;i{
if(a[i]>=a[i+1])
{
max[j++]=a[i];
min[k++]=a[i+1];
}
else
{
max[j++]=a[i+1];
min[k++]=a[i];
}
}
for(inti=0;i{
cout<<"max["<
cout<<"min["<
}
intMAX=max[0];
intMIN=min[0];
for(j=1;j{
if(max[j]>MAX)MAX=max[j];
if(min[j]}
cout<<"MAX="<}
intmain(void)
{
inta[]={6,16,3,13,6,5,7,8,9,10,2,8,6};
intn=sizeof(a)/sizeof(a[0]);
Max_Min(a,n);
system("pause");
return0;
}
3.3运行示例