归并排序(递归实现+非递归实现+自然合并排序)
来源:互联网 发布:silhouette软件 编辑:程序博客网 时间:2024/05/16 07:13
http://www.cnblogs.com/liushang0419/archive/2011/09/19/2181476.html
归并排序的确是分治思想的经典代表。写了很多次,这次又有新的收获,过去用的是递归的实现方式,理论上任何用递归方法实现的代码都可以转换为非递归的形式,所以此例也不例外。然后再用非递归的实现方法上进行改进,完成了“自然归并”算法,这比直接归并效率要高一些。
先给出基础的用递归方法实现的归并排序:
View Code
#include<iostream>using namespace std;const int SIZE = 100;int arr[SIZE];//排序数组arr[fir:end]void mergeSort(int fir,int end){ //当子序列就只有一个元素的时候就弹出 if(fir==end)return; //分治 int mid = (fir+end)/2; mergeSort(fir,mid); mergeSort(mid+1,end); //合并 int tempArr[SIZE]; int fir1=fir,fir2=mid+1; for(int i=fir;i<=end;i++){ if(fir1>mid) tempArr[i]=arr[fir2++]; else if(fir2>end) tempArr[i]=arr[fir1++]; else if(arr[fir1]>arr[fir2]) tempArr[i]=arr[fir2++]; else tempArr[i]=arr[fir1++]; } for(int i=fir;i<=end;i++) arr[i]=tempArr[i];}int main(){ //测试 int n;cin>>n; for(int i=0;i<n;i++)cin>>arr[i]; mergeSort(0,n-1); for(int i=0;i<n;i++)cout<<arr[i]<<" "; cout<<endl; return 0;}
其中归并函数中的合并方法没有单独写开,单独函数merge()及其解释如下:
void merge(int fir,int end,int mid){ //合并 int tempArr[SIZE]; int fir1=fir,fir2=mid+1; for(int i=fir;i<=end;i++){ if(fir1>mid)//前半段扫描完毕 tempArr[i]=arr[fir2++]; else if(fir2>end)//后半段扫描完毕 tempArr[i]=arr[fir1++]; //两端如果都没有扫描完毕的话 //就选择较小的值插在临时数组的后端 else if(arr[fir1]>arr[fir2]) tempArr[i]=arr[fir2++]; else tempArr[i]=arr[fir1++]; } //将排好的临时数组拷贝到原数组中,返回 for(int i=fir;i<=end;i++) arr[i]=tempArr[i];}
有了merge函数后mergesort1()如下:
void mergeSort(int fir,int end){ //当子序列就只有一个元素的时候就弹出 if(fir==end)return; //分治,现分为两个子段, int mid = (fir+end)/2; mergeSort(fir,mid);//对左半段递归排序 mergeSort(mid+1,end);//对右半段递归排序 //合并 merge();}
归并排序的非递归实现如下,思想和递归正好相反,原来的递归过程是将待排序集合一分为二,直至排序集合就剩下一个元素位置,然后不断的合并两个排好序的数组。所以非递归思想为,将数组中的相邻元素两两配对。用merge函数将他们排序,构成n/2组长度为2的排序好的子数组段,然后再将他们排序成长度为4的子数组段,如此继续下去,直至整个数组排好序。
代码如下:(和书上不同,自认为更好理解一些)
void mergeSort2(int n){ int s=2,i; while(s<=n){ i=0; while(i+s<=n){ merge(i,i+s-1,i+s/2-1); i+=s; } //处理末尾残余部分 merge(i,n-1,i+s/2-1); s*=2; } //最后再从头到尾处理一遍 merge(0,n-1,s/2-1);}
自然合并排序
该排序需要一个叫做pass()的子函数,该函数通过一次扫描,将排序前数组中已经有序的子数组段信息记录在rec[]数组中,然后返回原数组中自然序列的个数。
该算法的实现示意图见课本P23笔记。
// 自然归并是归并排序的一个变形,效率更高一些,可以在归并排序非递归实现的基础上进行修改//对于已经一个已经给定数组a,通常存在多个长度大于1的已经自然排好的子数组段//因此用一次对数组a的线性扫描就可以找出所有这些排好序的子数组段//然后再对这些子数组段俩俩合并//代码的实现如下:#include<iostream>using namespace std;const int SIZE = 100;int arr[SIZE];int rec[SIZE];//记录每个子串的起始坐标//排序数组arr[fir:end]//合并操作的子函数void merge(int fir,int end,int mid);//扫描得到子串的子函数int pass(int n);//自然合并函数void mergeSort3(int n);/********************************************************************/void mergeSort3(int n){ int num=pass(n); while(num!=2){ //num=2说明已经排好序了 //每循环一次,进行一次pass()操作 for(int i=0;i<num;i+=2) //坐标解释可参加P23页的图示 merge(rec[i],rec[i+2]-1,rec[i+1]-1); num=pass(n); }}void merge(int fir,int end,int mid){ //合并 int tempArr[SIZE]; int fir1=fir,fir2=mid+1; for(int i=fir;i<=end;i++){ if(fir1>mid) tempArr[i]=arr[fir2++]; else if(fir2>end) tempArr[i]=arr[fir1++]; else if(arr[fir1]>arr[fir2]) tempArr[i]=arr[fir2++]; else tempArr[i]=arr[fir1++]; } for(int i=fir;i<=end;i++) arr[i]=tempArr[i];}int pass(int n){ int num=0; int biger=arr[0]; rec[num++]=0; for(int i=1;i<n;i++){ if(arr[i]>=biger)biger=arr[i]; else { rec[num++]=i; biger=arr[i]; } } //给rec[]加一个尾巴,方便排序 rec[num++]=n; return num;}int main(){ int n; while(cin>>n){ for(int i=0;i<n;i++)cin>>arr[i]; //测试mergeSort函数 /**/mergeSort3(n); for(int i=0;i<n;i++)cout<<arr[i]<<" "; cout<<endl; //测试pass函数 /*int num = pass(n); for(int i=0;i<num;i++)cout<<rec[i]<<" "; cout<<endl;*/ } return 0;}
- 归并排序(递归实现+非递归实现+自然合并排序)
- 归并排序递归及非递归实现(自然合并排序)
- 归并排序三种实现方法(递归、非递归和自然合并排序)
- 非递归实现归并排序
- 非递归实现归并排序
- 归并排序非递归实现
- 归并排序(非递归实现)
- 归并排序实现 递归 非递归
- 归并排序 递归和非递归实现
- 归并排序 递归与非递归实现
- 归并排序递归和非递归实现
- 归并排序非递归和递归实现
- 递归和非递归实现归并排序
- 归并排序递归与非递归实现
- 非递归实现合并排序
- 合并排序非递归实现
- 自然合并排序的java实现(合并排序的非递归实现)
- 递归归并排序和非递归归并排序(自然分组)
- uva 10177 - (2/3/4)-D Sqr/Rects/Cubes/Boxes?
- 带壳破解SMC补丁技术
- v$sql、v$sqlarea、v$sqltext、v$sql_plan的联系与区别
- MFMessageComposeViewController中文界面设定
- 黑马程序员-单例设计模式:懒汉式和饿汉式
- 归并排序(递归实现+非递归实现+自然合并排序)
- VB write#语句和print#语句
- Unity3D公告板
- 表扬一下csdn
- 感染系统文件实现自启动
- dd命令的高级应用
- php 验证码
- 利用linux中的gtk程序开发包写的计算器程序
- jquery中的循环技巧