2.3合并排序的递归、非递归算法,自然合并排序

递归算法

将待排元素分成大小大致相同的两个子集合,分别对这两个集合进行排序,最终将排好序的子集合合并。

2.3合并排序的递归、非递归算法,自然合并排序_第1张图片

#include  
#include  
  
void Merge(int s[],int t[],int b,int m,int e){//将s[b...m]与s[m+1...e]合并  
    int i=b;//i->前一个块  
    int j=m+1;//j->后一个块  
    int k=0;//k->t数组  
    while(i<=m&&j<=e){  
        if(s[i]<=s[j])t[k++]=s[i++];  
        else t[k++]=s[j++];  
    }  
    while(i<=m){  
        t[k++]=s[i++];  
    }  
    while(j<=e){  
        t[k++]=s[j++];  
    }  
    for(int i=0;i

非递归算法

有三个函数:

(1)Merge函数,用于合并两个有序子段。这个函数主要是用于将a数组中[l,m]区间和[m+1,r]区间的数有序的合并b数组的[l,r]区间。这里不同于递归方法里的Merge函数,b数组从l开始到r结束是有序的并且不用在Merge函数尾部将b数组的有序部分赋值给a数组(原因下面提到)。

(2)MergePass函数,这个函数的功能对于长为n数组进行归并,两个两个地合并长度为s的子段,当然我们的数组长度不可能每次正好满足“以s为子段长度时正好能两两合并,一个不多一个不少”。所以我们要对特殊情况进行判断:

 while(i<=n-2*s){//剩下不超过2s长度的元素
        Merge(x,y,i,i+s-1,i+2*s-1);
        i=i+2*s;
 }

在剩下的元素不能组成两个子段的时候分情况讨论:

a.当剩下元素可以凑成一个长为s子段,Merge(x,y,i,i+s-1,n-1);

b.当剩下元素连一个长为s的字段都凑不成时,我们直接将其略过(不排序)

(3)MergeSort函数,这个数组首先设一个临时数组b,与要归并的子段长度s,s初始为1,在s这次排好的序列体现在b数组上,a数组此时没变!然后将s+=s;可以开始两两合并之前长为s的子段啦!这次把b再合并到a上,所以一趟下来,最后a是“有序的”,这也是Merge函数里不用把数组b再赋给a的原因了,省了一趟赋值!

#include
#include
#include
using namespace std;

void Merge(int a[],int b[],int l,int m,int r){
    int i=l,j=m+1,k=l;
    while(i<=m&&j<=r){
        if(a[i]

自然合并排序

自然合并排序:对于初始给定的数组,通常存在多个长度大于1的已自然排好序的子数组段.例如,若数组a中元素为{4,8,3,7,1,5,6,2},则自然排好序的子数组段有{4,8},{3,7},{1,5,6},{2}.用一次对数组a的线性扫描就足以找出所有这些排好序的子数组段.然后将相邻的排好序的子数组段两两合并,构成更大的排好序的子数组段({3,4,7,8},{1,2,5,6}).继续合并相邻排好序的子数组段,直至整个数组已排好序.

所以我们可以设变量flag表示序列中有几段已经排好序的子段。

设数组t[flag]表示每个有序子段的第一个元素所在的位置。

代码如下:

#include
#include
#include
using namespace std;
int t[10],flag=0;

void Merge(int a[],int b[],int l,int m,int r){
    int i=l,j=m+1,k=l;
    while(i<=m&&j<=r){
        if(a[i]

(第一行输出的是t数组,标记每个有序段的起始位置

第二行输出的是排好序的数组)

你可能感兴趣的:(计算机算法设计与分析)