自然合併排序

自然合併排序是合併排序算法的一種改進, 對於初始給定的數組, 通常存在多個長度大於1的已自然排好序的子數組段.

例如, 若數組a中元素爲{1, 5, 2, 3, 6, 0, 7, 4, 8}, 則自然排好序的子數組段有{1, 5}, {2, 3, 6}, {0, 7}, {4, 8}. 用一次對數組a的線性掃描就足以找出所有這些排好序的子數組段. 然後將相鄰的排好序的子數組段兩兩合併,構成更大的排好序的子數組段({1, 2, 3, 5, 6}, {0, 4, 7, 8}).繼續合併相鄰排好序的子數組段,直至整個數組已排好序.

通常情況下, 按此方式進行合併排序所需的合併次數較少. 例如, 對於所給的n元素數組已排好序的極端情況, 自然合併排序算法不需要執行合併.

#include <iostream>

using namespace std;

typedef int Type;

void print(Type a[], int n)
{
    for (int i=0; i<n; ++i) {
        cout << a[i] << " ";
    }
    cout << endl;
}

void GetIndex(int a[], int t[], int n, int &m)
{
    // 記錄自然分組後每個子串的起始座標
    int j = 0;
    t[j++] = 0;
    for(int i = 0; i < n-1; i++) {
        if(a[i+1] < a[i]) {
            t[j++] = i+1;
        }
    }
    m = j;      // m爲自然分組的個數
}

void Merge(Type c[], Type d[], int l, int m, int r)
{
    // 合併c[l:m]和c[m+1:r]到d[1:r]
    int i = l, j = m + 1, k = l;
    while (i <= m && j <= r) {
        if (c[i] <= c[j]) {
            d[k++] = c[i++];
        } else {
            d[k++] = c[j++];
        }
    }
    if (i > m) {
        for (int q = j; q <= r; q++) {
            d[k++] = c[q];
        }
    } else {
        for (int q = i; q <= m; q++) {
            d[k++] = c[q];
        }
    }
}

void MergePass(Type x[], Type y[], Type t[], int s, int n, int cnt)
{
    // 合併自然分組後相鄰的子數組
    int i = 0;

    while(i <= cnt - 2 * s) {
        // 當自然分組後的子數組個數爲偶數時, r = n, 表示恰好兩兩合併
        int r = ((i + 2 * s) < cnt) ? t[i+2*s] : n;
        Merge(x, y, t[i], t[i+s]-1, r-1);
        i = i + 2 * s;
    }

    if(i + s < cnt) {
        Merge(x, y, t[i], t[i+s]-1, n-1);
    } else if (i < cnt) {
        // 剩餘元素直接複製
        for(int j = t[i]; j <= n - 1; j++) {
            y[j] = x[j];
        }
    }
}

void MergeSort(Type a[], Type t[], int n, int cnt)
{
    Type *b = new Type[n];
    int s = 1;

    while (s < cnt) {
        MergePass(a, b, t, s, n, cnt);      // 合併到數組b
        s += s;
        MergePass(b, a, t, s, n, cnt);      // 合併到數組a
        s += s;
    }

    delete[] b;
}

int main(int argc, char *argv[])
{
    Type a[] = {1, 5, 2, 3, 6, 0, 7, 4, 8};
    int len = sizeof(a) / sizeof(int);
    Type *t = new Type[len];
    int cnt;        // 記錄自然分組個數

    GetIndex(a, t, len, cnt);
    MergeSort(a, t, len, cnt);
    print(a, len);

    delete[] t;

    return 0;
}

這裏寫圖片描述

發佈了48 篇原創文章 · 獲贊 141 · 訪問量 28萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章