1. 程式人生 > >資料結構與演算法 C 歸併(Merge)排序(非遞迴)

資料結構與演算法 C 歸併(Merge)排序(非遞迴)

7-18 排序(25 分)

給定N個(長整型範圍內的)整數,要求輸出從小到大排序後的結果。

本題旨在測試各種不同的排序演算法在各種資料情況下的表現。各組測試資料特點如下:

資料1:只有1個元素;

資料2:11個不相同的整數,測試基本正確性;

資料3:103個隨機整數;

資料4:104個隨機整數;

資料5:105個隨機整數;

資料6:105個順序整數;

資料7:105個逆序整數;

資料8:105個基本有序的整數;

資料9:105個隨機正整數,每個數字不超過1000。

輸入格式:

輸入第一行給出正整數N(≤10​5​​),隨後一行給出N個(長整型範圍內的)整數,其間以空格分隔。

輸出格式:

在一行中輸出從小到大排序後的結果,數字間以1個空格分隔,行末不得有多餘空格。

輸入樣例:

11
4 981 10 -17 0 -20 29 50 8 43 -5

輸出樣例:

-20 -17 -5 0 4 8 10 29 43 50 981
非遞迴進行實現 思路很類似連結串列吧。方法也是倆個倆個的合併。
程式碼:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <ctype.h>
#define MAX 1000000
/** merge 排序 非遞迴實現**/
void swap(int x,int y) /**交換函式**/
{
    int z;
    z=y;
    y=x;
    x=z;
}
long long compare(long long x,long long y) /**比較函式**/
{
    if(x>=y)return 1;
    else return 0;
}
void conbine(long long *arr,int* idex,int x,int y) /**兩個陣列的合併(歸併排序內用來合併的函式)**/
{
    int p1=x,p2=y,head,next;              /** x,y 分別是陣列的第一個下標 實現 類似於連結串列 , head 是 頭 next 是 正在插入時指標
                                            idex 是 記錄 每個數的 指向下一個比他大的數的下標 **/


    if(compare(arr[x],arr[y]))             /**先找到 倆數組合並後的 第一個下標**/
    {
        head=next=y;
        p2=idex[p2];
    }
    else
    {
        head=next=x;
        p1=idex[p1];
    }
        while(p1>=0&&p2>=0)                  /** 倆陣列比較 小的出去**/
        {
            if(compare(arr[p1],arr[p2]))
            {
                idex[next]=p2;
                p2=idex[p2];
            }
            else
            {
                idex[next] =p1;
                p1=idex[p1];
            }
            next=idex[next];
        }
        while(p1>=0)                          /**再把剩的全踢出去**/
        {
            idex[next]=p1;
            p1=idex[p1];
            next=idex[next];
        }
        while(p2>=0)
        {
             idex[next]=p2;
             p2=idex[p2];
             next=idex[next];
        }
        idex[next]=-head;                     /**合併後陣列最後一個等於頭下標的負值**/
}
void merge(long long *arr,int *idex,int n) /**歸併排序**/
{
    int i=1,j,x,y,f;
    f=1;
    while(1)
    {


        while(i<=n&&idex[i]>0) i++;            /**迴圈 每次找倆個 陣列來合併**/
            if(i<=n) x=i++;
            else x=0;
        while(i<=n&&idex[i]>0) i++;
            if(i<=n) y=i++;
            else y=0;
        //printf("%d %d\n",x,y);
        if(x&&y)                               /**找到倆個 合併**/
        {
            conbine(arr,idex,-idex[x],-idex[y]);
            f=0;
        }
        /*for(j=1;j<=n;j++)
            printf("%d ",idex[j]);
        printf("\n");*/
        if(f) break;                          /**f 意義是如果 最後 只找到一個 負數(頭下標的負值)  就排好序了**/
        if(i>n)                        /** 小排序 一次後 進行第二次小排序**/
        {
            i=1;
            f=1;
        }
    }
}
void display(long long *arr,int *idex,int x)        /**用來輸出 不多說了**/
{
    //printf("->");
    int f=1;
    while(x>=0)
    {
        if(f) f=0;
        else printf(" ");
        printf("%lld",arr[x]);
        x=idex[x];
    }
}
int main(){
    int n,i,j;
    scanf("%d",&n);
    long long *arr;
    arr = (long long *)malloc((n+2)*sizeof(long long));  /** 陣列最好從 下標 1 開始 ,為了最後解決頭下標負數 0 = -0的矛盾**/
    for(i=1;i<=n;i++)
    {
        scanf("%lld",&arr[i]);
    }
    int *idex;
    idex=(int*)malloc((n+2)*sizeof(int));
    for(i=1;i<=n;i++)
        idex[i]=-i;
    merge(arr,idex,n);
    //conbine(arr,idex,1,2);
    for(i=1;i<=n;i++)
    {
        if(idex[i]<0)
        {
            display(arr,idex,-idex[i]);
            break;
        }
    }

return 0;
}