二路歸並排序


一、算法思想:

假設初始序列中含有N個記錄,則可以看成N個有序的子序列,每個子序列的長度為一,然后兩兩歸並,得到\([\frac{N}{2}]\)(表示不小於\(\frac{N}{2}\)的最小整數)個長度為2或者1的有序子序列:再兩兩歸並,如此重復,直到得到一個長度為N的有序子序列為止,稱為2路歸並排序(Merge Sort)。

image

二、算法實現

1、遞歸實現

1)排序原理

歸並排序的遞歸實現主要在於遞歸分治,對於遞歸算法,我們都能用二叉樹來理解,對於一個序列,遞歸左右子序列,並對其子序列進行合並排序,即可得到排序好的序列
排序過程圖示
image

2)代碼實現

#include<stdio.h>
#include<stdlib.h>
#define N 10
void Merge(int sort[],int num[],int low,int mid,int high)
{
    int i=low;      //左子序列起點下標
    int j=mid+1;    //右子序列起點下標
    int k=low;      //臨時數組的初始化下標
    while(i<=mid&&j<=high)//在左右子序列中按從小到大順序存到臨時數組中
    {
        if(num[i]<num[j])
            sort[k++]=num[i++];
        else
            sort[k++]=num[j++];
    }
    //將左右子序列剩余的數依次存入臨時數組
    while(i<=mid)
        sort[k++]=num[i++];
    while(j<=high)
        sort[k++]=num[j++];
    //將臨時數組的數據按位置復制到原數組對應位置上
    while(--k>=0)
        num[k]=sort[k];
}
void MergeSort(int sort[],int num[],int low,int high)
{
    if(low<high)
    {
        int mid=(low+high)/2;           //分為左右子序列的中間下標
        MergeSort(sort,num,low,mid);    //遞歸左子序列
        MergeSort(sort,num,mid+1,high); //遞歸右子序列
        Merge(sort,num,low,mid,high);   //排序
    }
}
int main()
{
    int *sort;
    int num[N]={5,3,7,1,9,2,0,4,8,6};
    sort=(int*)malloc(N*sizeof(int));
    MergeSort(sort,num,0,N-1);
    for(int i=0;i<N;i++)
        printf("%d ",num[i]);
    printf("\n");
    free(sort);
    return 0;
}

2、非遞歸實現

1)排序原理

歸並排序的非遞歸實現主要在於子序列的划分;
1、首先需要一個臨時數組以及左右兩個子序列的區間
2、從區間長度為1開始(遞增兩倍)將原數組划分成多對左右兩個子序列;
3、依次將多對左右子序列進行比較,並按順序存入臨時數組中
4、再將臨時數組排序好的序列再復制到原數組中
5、最后區間長度兩倍增長,重復以上操作,即歸並
排序過程圖示
image

2)代碼實現

#include<stdio.h>
#include<stdlib.h>
#define N 10
 
void MergeSort(int num[],int len)
{
    int i,j;
    int *sort;
    int L_start=0,L_end=0;//初始化左區間的起點、終點下標
    int R_start=0,R_end=0;//初始化右區間的起點、終點下標
 
    sort=(int*)malloc(N*sizeof(int));//為臨時數組分配空間
 
    for(i=1;i<N;i*=2)//區間長度兩倍遞增
    {
        for(L_start=0;L_start<len-i;L_start=R_end)
        {
            //確定左右區間兩邊的起點、終點下標
            L_end   = L_start+i;
            R_start = L_start+i;
            R_end   = R_start+i;
 
            if(R_end>len)//右區間終點不超過數組長度
            {
                R_end=len;
            }          
            j=0;    //臨時數組初始下標
 
            while(L_start<L_end && R_start<R_end)
            {
                //比較左右起點數據的大小,並將較小的數據依次存入臨時數組
                if(num[L_start]<num[R_start])   
                    sort[j++]=num[L_start++];
                else
                    sort[j++]=num[R_start++];
                //同時起點下標遞增
            }
     
            while(L_start<L_end)//將比較完剩余的數據存入臨時數組
            {
                sort[j++]=num[L_start++];
            }  
            while(j>0)           //將已排好的臨時數組數據錄入原數組中
            {
                num[--R_start]=sort[--j];
            }
 
            //for(int k=0;k<len;k++)
            // printf("%d ",num[k]);
            //printf("\n");
        }
    //printf("-------------\n");
    }
    free(sort);
}
 
int main()
{
    int num[N]={5,3,7,1,9,2,0,4,8,6};
    MergeSort(num,N);
    for(int i=0;i<N;i++)
        printf("%d ",num[i]);
    printf("\n");
    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM