[資料結構] MergeSort

合併排序演算法實作

特徵

1. 為 Stable 排序。

2. 因為需要額外空間,非 in-place algorithm。

** in-place algorithm 指的是使用較少空間處理的演算法。

(In-place is an algorithm which transforms input using a data structure with a small, constant amount of extra storage space.)

出處:維基百科

實作重點 (KEY POINT)

1. 進行分割 (直到無法再分割為止,以 "/2" 作為索引持續分割) lgN

2. 進行合併 (將分割後的值重新聚合,聚合的同時進行比較並排序) N

速度:N * lgN

以下為實作程式碼。

/**
 * Algorithm Course
 *
 * Homework Assignement #3
 * - find number of inversions in an arr (from input file with integers)
 *
 * @student ID: A889056
 * @name      : GiPyeongLee
 * @.agents/skills/caveman-compress/scripts/validate.py      : 2015.03.16
 **/

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "math.h"
#include "errno.h"
#include "sys/time.h"

#define MAX_NUM 1000000
unsigned long cnt = 0;

void seperate(int *arr,int left,int right);
void merge(int *arr,int left,int mid,int right);
void count_inversion (int *data, int left, int right) {
    seperate(data,left,right); // seperate and merge
}
void seperate(int *arr,int left,int right){
    if(left < right){
        int mid;
        mid=(left+right)/2;
        seperate(arr,left,mid);
        seperate(arr,mid+1,right);
        merge(arr,left,mid,right);
    }
}
void merge(int *arr,int left,int mid,int right){
    int tempArr[right-left+1];
    int pos=0,lpos = left,rpos = mid + 1;
    while(lpos <= mid && rpos <= right)
    {
        if(arr[lpos] < arr[rpos])
        {
            tempArr[pos++] = arr[lpos++];
        }
        else
        {
            cnt+=(mid-lpos+1);
            tempArr[pos++] = arr[rpos++];

        }
    }
    while(lpos <= mid)  tempArr[pos++] = arr[lpos++];
    while(rpos <= right)tempArr[pos++] = arr[rpos++];
    int iter;
    // iterator to pos , tempArr to arr.
    for(iter = 0;iter < pos; iter++)
    {
        arr[iter+left] = tempArr[iter];
    }
    return;
}

int main(int argc, char *argv[]) {
    char *filename;
    FILE *fp;
    char str[10];
    int number;
    unsigned int N;
    int data[MAX_NUM] = {};
    clock_t start_time,end_time;


    if (argc > 1) {
        filename = argv[1];
    } else {
        printf("no input file argument\n");
        return -1;
    }

    if ((fp = fopen(filename, "r")) == NULL) {
        printf("Error opening input file\n");
        return -1;
    }

    while (fgets(str, 10, fp) != NULL) {
        if (N >= MAX_NUM) {
            printf("too many data\n");
            break;
        }
        number = strtol(str, NULL, 10);
        if (errno == EINVAL)
            break;
        data[N] = number;
        N++;
    }
    start_time=clock();
    printf("INPUT : Number of data     N = %d\n", N);

    count_inversion(data, 0, N - 1);

    printf("OUTPUT: Number of inversions = %lu\n", cnt);

    end_time = clock();

    printf("running time = %f seconds\n",((double)(end_time-start_time))/CLOCKS_PER_SEC);

    return 0;
}

透過上述合併排序完成了作業,該作業要求計算反轉 (Inversion) 的總情況數。

使用上述程式碼,得到了以下的結果。

顯示更多


$ ./count_inversions hw3_input_10k.txt INPUT : Number of data N = 10000 OUTPUT: Number of inversions = 23948130 running time = 0.002207 seconds $ $ ./count_inversions hw3_input.txt INPUT : Number of data N = 100000 OUTPUT: Number of inversions = 2407905288 running time = 0.019184 seconds $ $ ./count_inversions hw3_input_1000k.txt INPUT : Number of data N = 1000000 OUTPUT: Number of inversions = 249953281796 running time = 0.227101 seconds
AD