二路归并排序(未完)

注:归并算法是典型的分治法实例,即将一个大问题分解为n个原子问题(不可再分割),将这n个小问题解决后再逐渐合并,一般使用的是递归法。归并排序是一种交稳定的排序算法,时间复杂度固定式nlogn,但在实际操作中,其时间复杂度将会远远大于该值,因为在代码执行过程中不停的申请临时内存和释放内存,

归并排序的优化

归并排序的图解

递归实现二路归并排序

#include<iostream>
#include<vector>
using namespace std;
void merge(int arr[],int min,int m,int max){ 
int *tem=new int [max-min+1];
int k=0,i=min,j=m+1;
while(i<=m&&j<=max){
if(arr[i]>arr[j])
	tem[k++]=arr[j++];
else
	tem[k++]=arr[i++];	
} 
while(i<=m)tem[k++]=arr[i++];
while(j<=max)tem[k++]=arr[j++];
//for(int l=0;l<=max-min;l++)
//arr[l]=tem[l];//此处传递值是错误的,因为在一次循环中完成的是min到max的排序,
//只要把该区间的数值传递即可
for(int l=min,p=0;l<=max;p++,l++)
arr[l]=tem[p];
for(int ll=0;ll<10;ll++)//改代码可以清晰的看见排序过程,每次执行该函数的时候,
//就是对min到max的排序,而且在排序结束之后改变了原arr数组的值
cout<<arr[ll];
cout<<endl<<"-----------------"<<endl;
}
void Msort(int arr[],int min,int max){
	if(min>=max)
	return;
	else{
		Msort(arr,min,(min+max)/2);
		Msort(arr,(max+min)/2+1,max);
		merge(arr,min,(min+max)/2,max);
	}
}
int main(){
int arr[]={0,7,2,5,1,3,4,6,9,8};
Msort(arr,0,9);
for(int i=0;i<10;i++)
cout<<arr[i];
return 0;
} 

分析:如果对Merge的每个递归调用均局部声明一个临时数组,那么在任意时刻就可能有logn个数组处在活动期,对内存是一个极大的消耗。另外在分配和收回上也会消耗很多时间。

时间复杂度的推算很复杂,涉及到叠缩求和,我认为在Msort函数中调用了logn次merge函数,在merge函数的排序的时间复杂度是N所以整个的时间复杂度是nlogn


另外二路归并排序的迭代做法有效的防止了栈溢出,但是代码不够简洁,等我摸清楚后再更新

迭代实现二路递归排序

#include<iostream>
#include<algorithm>
using namespace std;
void merge(int arr[],int min,int m,int max){ 
int *tem=new int [max-min+1];
int k=0,i=min,j=m+1;
while(i<=m&&j<=max){
if(arr[i]>arr[j])
	tem[k++]=arr[j++];
else
	tem[k++]=arr[i++];	
} 
while(i<=m)tem[k++]=arr[i++];
while(j<=max)tem[k++]=arr[j++];
for(int l=min,p=0;l<=max;p++,l++)
arr[l]=tem[p];
for(int ll=0;ll<10;ll++)
cout<<arr[ll];
cout<<endl<<"-----------------"<<endl;
}
void Msort(int arr[],int n){
	for(int step=2;step/2<=n;step*=2){//step表示步长,至于为什么是2的次幂,
	//我想应该是对应logn,
		for(int i=0;i<=n;i+=step){
				merge(arr,i,i+step/2-1,min(n-1,i+step-1));	
		}
	} 
}
int main(){
int arr[]={9,8,7,6,5,4,3,2,1,0};
Msort(arr,10);
for(int i=0;i<10;i++)
cout<<arr[i];
return 0;
}

分析:其实递归和非递归的merge函数基本没什么变化,主要思想就是怎么将目标序列拆分,并按传入merge函数,merge(arr,i,i+step/2-1,min(n-1,i+step-1));中的i+step/2-1表示传入区间的中点,注意,该中点并非(min+max)/2,比如在区间为0 1 2 3 4 5 6 7 8 9 中,当步长为8时,前后区间的个数分别为8和2.

本来想使用vector数组,这样省去了动态申请数组的过程,无奈道行太浅,怎么都调试不出来。稍后再试试。

猜你喜欢

转载自blog.csdn.net/Cai__ji/article/details/84933084