アルゴリズムとデータ構造:マージソート
クイックソートは元データの並びが悪いとバブルソートと同じくらい効率が悪い。
もっと確実に効率の良い方法はないかということでマージソートがありますよ、と。
クイックソートよりも最悪計算量が少ない。
[マージソートの計算量]
最悪:O(N Log N)
[ソースコード:merge_sort.c]
#include <stdio.h> #include <stdlib.h> #include <time.h> #define N 8 /* データ件数 */ int sort[N]; int buffer[N]; int count; /* 交換回数 */ void MergeSort(int n, int x[]); void output(int list[],int j,char *name); void MergeSort(int n, int x[]) { int i, j, k, m; if(n <= 1){ return; } m = n / 2; /* ブロックを前半と後半に分ける */ MergeSort(m, x); MergeSort(n - m,x + m); /* 併合(マージ)操作 */ for(i = 0; i < m; i++){ buffer[i] = x[i]; } output(buffer,i,"buffer"); output(x+m,m,"x"); j = m; i = k = 0; while(i < m && j < n){ if(buffer[i] <= x[j]){ x[k++] = buffer[i++]; } else{ x[k++] = x[j++]; } output(sort,N,"sort"); ++count; } while(i < m){ x[k++] = buffer[i++]; output(sort,N,"sort"); } printf("-- result --\n"); output(sort,N,"sort"); printf("\n"); } int main(void){ int i; clock_t start,end; srand((unsigned int) time (NULL)); printf("Standby...\n"); for(i = 0; i < N; i++){ /* ランダムな数値を格納 */ sort[i] = rand() % 10 + 1; } output(sort,N,"sort"); printf("\n<< Start >>\n"); start = clock(); MergeSort(N, sort); end = clock(); printf("\n<< End >>\n"); output(sort,N,"sort"); printf("Count:%d\n",count); printf("Time:%.2f\n",(double)(end-start)/CLOCKS_PER_SEC); return EXIT_SUCCESS; }
データ件数8件、1〜10の乱数を発生させて実行した結果
$ ./merge_sort Standby... sort => [6,10,4,8,2,6,7,5] << Start >> buffer => [6] x => [10] sort => [6,10,4,8,2,6,7,5] -- result -- sort => [6,10,4,8,2,6,7,5] buffer => [4] x => [8] sort => [6,10,4,8,2,6,7,5] -- result -- sort => [6,10,4,8,2,6,7,5] buffer => [6,10] x => [4,8] sort => [4,10,4,8,2,6,7,5] sort => [4,6,4,8,2,6,7,5] sort => [4,6,8,8,2,6,7,5] sort => [4,6,8,10,2,6,7,5] -- result -- sort => [4,6,8,10,2,6,7,5] buffer => [2] x => [6] sort => [4,6,8,10,2,6,7,5] -- result -- sort => [4,6,8,10,2,6,7,5] buffer => [7] x => [5] sort => [4,6,8,10,2,6,5,5] sort => [4,6,8,10,2,6,5,7] -- result -- sort => [4,6,8,10,2,6,5,7] buffer => [2,6] x => [5,7] sort => [4,6,8,10,2,6,5,7] sort => [4,6,8,10,2,5,5,7] sort => [4,6,8,10,2,5,6,7] -- result -- sort => [4,6,8,10,2,5,6,7] buffer => [4,6,8,10] x => [2,5,6,7] sort => [2,6,8,10,2,5,6,7] sort => [2,4,8,10,2,5,6,7] sort => [2,4,5,10,2,5,6,7] sort => [2,4,5,6,2,5,6,7] sort => [2,4,5,6,6,5,6,7] sort => [2,4,5,6,6,7,6,7] sort => [2,4,5,6,6,7,8,7] sort => [2,4,5,6,6,7,8,10] -- result -- sort => [2,4,5,6,6,7,8,10] << End >> sort => [2,4,5,6,6,7,8,10] Count:16 Time:0.00
データ件数を100000000にして実行しても1分弱で
クイックソートのときよりも多い件数でもちゃんと計算できた。
ログが上手く吐けなく前回から随分日が経ってしまった。
x[k++]の挙動を考えれば当たり前なのですが、すぐ気付けなかった。
x[k++] = buffer[i++];ってやってる箇所の直線で
printf("x[%d]:%d = buffer[%d]:%d",k++,x[k++],i++,buffer[i++]);とかやっちゃって。
そりゃもう、結果もめちゃくちゃですよねえ。
これでやっと次に行ける。