2015-12-18 第十六週 項目3 - 歸併排序算法的改進

1.問題及代碼

#include <stdio.h>  
#include <malloc.h>  
#include <stdlib.h>  
#include <time.h>  
#define MinLength 64        //最短分段長度  
typedef int KeyType;    //定義關鍵字類型  
typedef char InfoType[10];  
typedef struct          //記錄類型  
{  
    KeyType key;        //關鍵字項  
    InfoType data;      //其他數據項,類型爲InfoType  
} RecType;              //排序的記錄類型定義  
  
void GetData(RecType *&R, int n)  
{  
    srand(time(0));  
    R=(RecType*)malloc(sizeof(RecType)*n);  
    for(int i=0; i<n; i++)  
        R[i].key= rand();  
    printf("生成了%d條記錄\n", n);  
}  
  
//對R[low..high]按遞增有序進行直接插入排序  
void InsertSort(RecType R[],int low,int high)  
{  
    int i,j;  
    RecType tmp;  
    for (i=low; i<=high; i++)  
    {  
        tmp=R[i];  
        j=i-1;            //從右向左在有序區R[low..i-1]中找R[i]的插入位置  
        while (j>=low && tmp.key<R[j].key)  
        {  
            R[j+1]=R[j]; //將關鍵字大於R[i].key的記錄後移  
            j--;  
        }  
        R[j+1]=tmp;      //在j+1處插入R[i]  
    }  
}  
  
//合併兩個有序表  
void Merge(RecType R[],int low,int mid,int high)  
{  
    RecType *R1;  
    int i,j,k;  
    i=low,j=mid+1,k=0; //k是R1的下標,i、j分別爲第1、2段的下標  
    R1=(RecType *)malloc((high-low+1)*sizeof(RecType));  //動態分配空間  
    while (i<=mid && j<=high)       //在第1段和第2段均未掃描完時循環  
        if (R[i].key<=R[j].key)     //將第1段中的記錄放入R1中  
        {  
            R1[k]=R[i];  
            i++;  
            k++;  
        }  
        else                            //將第2段中的記錄放入R1中  
        {  
            R1[k]=R[j];  
            j++;  
            k++;  
        }  
    while (i<=mid)                      //將第1段餘下部分複製到R1  
    {  
        R1[k]=R[i];  
        i++;  
        k++;  
    }  
    while (j<=high)                 //將第2段餘下部分複製到R1  
    {  
        R1[k]=R[j];  
        j++;  
        k++;  
    }  
    for (k=0,i=low; i<=high; k++,i++) //將R1複製回R中  
        R[i]=R1[k];  
}  
  
//一趟合併  
void MergePass(RecType R[],int length,int n)    //對整個數序進行一趟歸併  
{  
    int i;  
    for (i=0; i+2*length-1<n; i=i+2*length)     //歸併length長的兩相鄰子表  
        Merge(R,i,i+length-1,i+2*length-1);  
    if (i+length-1<n)                       //餘下兩個子表,後者長度小於length  
        Merge(R,i,i+length-1,n-1);          //歸併這兩個子表  
}  
  
//自底向上的二路歸併算法,但太短的分段,用直接插入完成  
void MergeSort(RecType R[],int n)  
{  
    int length, i;  
    for(i=0;i<n;i+=MinLength)   //先按最短分段,用插入排序使之分段有序  
        InsertSort(R, i, ((i+MinLength-1<n)?(i+MinLength-1):n));  
    for (length=MinLength; length<n; length=2*length) //進行歸併  
    {  
        MergePass(R,length,n);  
    }  
}  
int main()  
{  
    int i,n=10000;  
    RecType *R;  
    GetData(R, n);  
    MergeSort(R,n);  
    printf("排序後(前300個):\n");  
    i=0;  
    while(i<300)  
    {  
        printf("%12d ",R[i].key);  
        i++;  
        if(i%5==0)  
            printf("\n");  
    }  
    printf("\n");  
    printf("排序後(後300個):\n");  
    i=0;  
    while(i<300)  
    {  
        printf("%12d ",R[n-300+i].key);  
        i++;  
        if(i%5==0)  
            printf("\n");  
    }  
    printf("\n");  
    free(R);  
    return 0;  
}  


2.運行結果




3.知識總結

  排序改進。

4.學習心得

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章