实验4递归与分治策略的应用Word文档格式.docx
《实验4递归与分治策略的应用Word文档格式.docx》由会员分享,可在线阅读,更多相关《实验4递归与分治策略的应用Word文档格式.docx(21页珍藏版)》请在冰豆网上搜索。
运行到一定规模:
快速排序:
堆排序:
矩阵乘法:
1朴素算法:
2Strassen矩阵乘算法
一定规模后:
总
横坐标计算规模:
1:
81292:
655363:
1310724:
2621445:
1048576
随着输入规模的增大,通过三种算法的时间记录做成折线图观察不难发现,在初期,三种算法所用时间几乎相等,随着输入规模的不断增大,堆排序和快速排序仍然能够保持相对较小的增长,而并归排序所用时间复杂度开始大幅度增加。
快速排序果然是快,数据越大优势越明显,并且实现上也较为简单。
理论上它的平均时间和归并排序,堆排序都是一样的(在最坏情况还还不如它们),都是O(nlog2n),但实际运行来看比它们两者的速度都快一倍以上。
COOL!
合并排序需要额外相同规模的数组,空间复杂度为O(n)。
从具体实现来看,这只是一种理论上的优秀算法,想法比较简单直接,但实现上比quicksort
复杂,运行时间也差,在数据很大的时候运行时间是heapsort的两倍,更不用说quicksort了。
堆排序利用了二分树的结构,将时间复杂度降到O(nlog2n),理论上和实现上表现都不错,并且发现在数据量是10
000
000时,甚至优于快排,可能是运行时数据的问题。
对于strassen算法对其时间复杂度分析:
T(n)=7T(n/2)+O(n);
而朴素算法的时间复杂度为n的三次方。
随着数据增大,也出现乘方级别的时间复杂度差距。
附
录
//头文件
#include<
iostream>
stdio.h>
windows.h>
time.h>
string.h>
#definePARENT(i)(i/2)//几个较简单函数
#defineLEFT(i)(2*i+1)
#defineRIGHT(i)(2*i+2)
usingnamespacestd;
//定义所需要变量等
#defineMAX100000
inta[MAX];
//数组存储原始顺序
inttemp[MAX];
//临时数组存储临时排序值
intnum;
//计算统计逆序对数
intN=2;
//数据规模
clock_tbegintimes,endtimes;
//clock_t为clock()函数返回的变量类型
doubleduration;
//运行时间计算
intheapsize;
//堆长度
//随机生成数函数
intnumber(){
inta;
a=rand()%10000+1;
//随机生成1到一万之间的整数
returna;
}
//初始化函数对数组a[]初始化。
voidinit(){
memset(temp,0,MAX*sizeof(int));
//临时数组清零
for(inti=0;
i<
N;
i++){//新数组赋值
a[i]=number();
}
return;
//单次并归挑选
voidMerge(intleft,intmid,intright)//需要三个参数,将原来数组分割
{
inti=left,j=mid+1,n=0,length=right-left;
//i开始为左半部分最左边,j为右半部分最左边
while(i<
=mid&
&
j<
=right){//未超限进行循环填数
if(a[i]>
a[j]){//左边比右边大
temp[n++]=a[j++];
num+=mid-i+1;
//从i到mid都比a[j]大
}
else{
temp[n++]=a[i++];
if(i>
mid){//左边全部填满了,填右边
while(j<
=right){
else{//右边填满,填左边
while(i<
=mid){
for(intk=0;
k<
=length;
k++){//最后临时数组赋值到原数组
a[left+k]=temp[k];
//递归进行并归排序
voidMergeSort(intleft,intright)
if(left<
right){
intmid=(left+right)/2;
MergeSort(left,mid);
MergeSort(mid+1,right);
Merge(left,mid,right);
//快速排序一次
intPartition(intleft,intright)
inti=left-1;
for(intj=left;
=right-1;
j++){
if(a[j]<
a[right]){//把right作为轴
i++;
//这个i坐标左边的值是比a[right]小的
swap(a[i],a[j]);
//交换
swap(a[i+1],a[right]);
//最后把i+1和right交换,这样轴就是i+1了必须是保证i+1上当初就是作为标杆的a[right]啊。
returni+1;
//递归进行快排整体
voidQuickSort(intleft,intright){
intq=Partition(left,right);
QuickSort(left,q-1);
QuickSort(q+1,right);
//堆排序,函数太多,新建一个命名空间
namespaceMySort{
template<
typenameT>
//堆排序的大顶堆优化(找数)
voidMax_Heapify(T*arr,inti,size_theapSize){
//从元素A[i]、A[LEFT(i)]、A[RIGHT(i)]中找出最大的,并将其下标保存在Largest中
//size_theapSize=sizeof(arr)/sizeof(*(arr));
也就是数量n
intl=LEFT(i);
intr=RIGHT(i);
intlargest;
//寻找
if(l<
heapSize&
*(arr+l)>
*(arr+i))
largest=l;
else
largest=i;
if(r<
*(arr+r)>
*(arr+largest))
largest=r;
if(largest!
=i){
swap(*(arr+i),*(arr+largest));
Max_Heapify(arr,largest,heapSize);
//如果A[i]是最大的,则以i为根的子树已经是最大堆
//建立大顶堆,采用上面大顶堆方法进行优化
voidBuild_Max_Heap(T*arr,size_theapSize){//从底部开始进行向上优化
for(inti=heapSize/2-1;
i>
=0;
i--)
Max_Heapify(arr,i,heapSize);
template<
//获得最大顶堆,堆排序开始,即元素出堆
voidHeapSort(T*arr,size_theapSize){
Build_Max_Heap(arr,heapSize);
for(inti=heapSize-1;
0;
i--){
swap(*arr,*(arr+i));
Max_Heapify(arr,0,i);
intmain(){
N=2;
do{
N*=2;
//依次增大计算规模
srand((unsigned)time(NULL));
//给一个时间种子
init();
//初始化一次
cout<
<
"
进行规模为"
<
N<
的排序"
endl;
原始数组为:
"
;
for(inti=0;
i++){
cout<
a[i]<
begintimes=clock();
//计时开始
MergeSort(0,N-1);
QuickSort(0,N-1);
MySort:
:
HeapSort<
int>
(a,N);
endtimes=clock();
//计时结束
duration=1000*(double)(endtimes-begintimes)/CLK_TCK;
//总共用时(毫秒)
排序后数组为:
此次用时为"
duration<
毫秒"
endl<
//记录实验结果,注意运行一次手动进行数据转移,清除数据
FILE*fpWrite1=fopen("
data1.txt"
"
a+"
);
//记录实验结果
fprintf(fpWrite1,"
%d\n"
N);
fclose(fpWrite1);
FILE*fpWrite2=fopen("
data2.txt"
fprintf(fpWrite2,"
duration);
fclose(fpWrite2);
}while(duration<
180000);
//单次时间小于3分钟
return0;
#defineMAX10000
intN;
a=rand()%100+1;
//最朴素算法三重循环
voidpusu(int**arr,int**brr,int**crr){
=N-1;
i++){
for(intj=0;
j++){
for(intk=0;
k++){
crr[i][j]+=arr[i][k]*brr[k][j];
}
//Strassen矩阵乘法算法,矩阵分块,仅仅针对2的n次幂次阶处理
voidgerResultStrassen(int**arr,int**brr,intn,int**crr){
if(n==1){
crr[0][0]+=arr[0][0]*brr[0][0];
else{
intm=n/2;
int**arr11=newint*[m];
int**arr12=newint*[m];
int**arr21=newint*[m];
int**arr22=newint*[m];
int**brr11=newint*[m];
int**brr12=newint*[m];
int**brr21=newint*[m];
int**brr22=newint*[m];
int**crr11=newint*[m];
int**crr12=newint*[m];
int**crr21=newint*[m];
int**crr22=newint*[m];
m;
++i){
arr11[i]=newint[m];
arr12[i]=newint[m];
arr21[i]=newint[m];
arr22[i]=newint[m];
brr11[i]=newint[m];
brr12[i]=newint[m];
brr21[i]=newint[m];
brr22[i]=newint[m];
crr11[i]=newint[m];
crr12[i]=newint[m];
crr21[i]=newint[m];
crr22[i]=newint[m];
}//获取矩阵
//四块矩阵的分别计算
//11
for(intj=0;
++j){
arr11[i][j]=arr[i][j];
brr11[i][j]=brr[i][j];
//22
for(inti=m;
n;
for(intj=m;
arr22[i-m][j-m]=arr[i][j];
brr22[i-m][j-m]=brr[i][j];
//12
arr12[i][j-m]=arr[i][j];
brr12[i][j-m]=brr[i][j];
//21
arr21[i-m][j]=arr[i][j];
brr21[i-m][j]=brr[i][j];
crr11[i][j]=0;
crr12[i][j]=0;
crr21[i][j]=0;
crr22[i][j]=0;
//递归分治
gerResultStrassen(arr11,brr11,m,crr11);
gerResultStrassen(arr12,brr21,m,crr11);
gerResultStrassen(arr11,brr12,m,crr12);
gerResultStrassen(arr12,brr22,m,crr12);
gerResultStrassen(arr21,brr11,m,crr21);
gerResultStrassen(arr22,brr21,m,crr21);
gerResultStrassen(arr21,brr12,m,crr22);
gerResultStrassen(arr22,brr22,m,crr22);
//一下是矩阵的分为四块
crr[i][j]+=crr11[i][j];
crr[i][j]+=crr22[i-m][j-m];
crr[i][j]+=crr12[i][j-m];
crr[i][j]+=crr12[i-m][j];
//后期处理
delete[]arr11[i];
delete[]brr11[i];
delete[]crr11[i];
delete[]arr12[i];
delete[]brr12[i];
delete[]crr12[i];
delete[]arr21[i];
delete[]brr21[i];
delete[]crr21[i];
delete[]arr22[i];
delete[]brr22[i];
delete[]crr22[i];
delete[]arr11;
delete[]brr11;
delete[]crr11;
delete[]arr12;
delete[]brr12;
delete[]crr12;
delete[]arr21;
delete[]brr21;
delete[]crr21;
delete[]arr22;
delete[]brr22;
delete[]crr22;
//初始化函数
voidinit(int**arr,int**brr,int**crr){
//初始化赋值
arr[i][j]=number();
crr[i][j]=0;
brr[i][j]=number();
//输出函数
voidinput(int**arr,int**brr,int**crr){
cout<
矩阵A\n"
++i)
{
++j)
{
arr[i][j]<
矩阵B\n"
brr[i][j]<
相乘后的矩阵C\n"
crr[i][j]<
所用时间为:
//主函数
intmain()
//矩阵的阶数
N=N*2;
int**arr=newint*[N];
//定义数组,分别存放三个矩阵
int**brr=newint*[N];
int**crr=newint*[N];
//获取矩阵
arr[i]=newint[N];
brr[i]=newint[N];
crr[i]=newint[N];
//给一个时