排序

1.  排序的幾個概念

     (1)內部排序與外部排序:

               整個過程都在內存中進行,則叫內部排序;否則爲外部排序。

     (2)主關鍵字和次關鍵字:

               若排序過程中主關鍵字相同,則使用次關鍵字進行比較。

     (3)排序的穩定性:

               若排序前Ki  = Kj (i < j),排序後仍然如此,則穩定;否則不穩定。

2.  算法實例

     2.1  直接插入排序:在已排好序的集合上繼續插入一個元素構成新的集合。

            部分代碼(完整代碼直接插入.c):

 

void insert_sort (RecordType *r, int l)
{
    /* 數組元素 r[0]是監視哨 */
    int     i, j;
    for (i = 2; i <= l; i++) {
        r[0] = r[i];
        /* 從後向前比較,邊比較邊移動 */
        for (j = i-1; r[0].key < r[j].key; j--) 
            r[j+1] = r[j];
        r[j+1] = r[0];
    }
}
           時空複雜度:T(n) = O(n2), S(n) = O(1)


    2.2  折半插入排序:利用折半的思想在 {1...i-1} 中查找 i 的位置

            部分代碼(完整代碼折半插入.c):

void insert_sort (RecordType *r, int l) 
{
    /* 數組元素 r[0]是監視哨 */
    int     i, j;
    int     low, high, mid;

    for (i = 2; i <= l; i++) {
        r[0] = r[i];

        low = 1, high = i - 1;
        while (low <= high) {
            mid = (low + high)/2;
            if (r[0].key < r[mid].key) 
                high = mid-1;
            else 
                low = mid + 1;
        }

        for (j = i-1; j >= low; j--) 
            r[j+1] = r[j];
        r[low] = r[0];
    }
}
           時空複雜度:T(n) = O(n2), S(n) = O(1)

     2.3  shell排序:分組,組內進行直接插入排序的思想,多次重複減小組內間距

             部分代碼(完整代碼shell排序.c

void shell_insert (int r[], int l, int delta)
{
    int     i, j;
    for (i = 1+delta; i <= l; i++) {
        if (r[i] < r[i-delta]) {
            r[0] = r[i];

            // 組內進行直接插入排序
            for (j = i-delta; j > 0 && r[0] < r[j]; j-=delta) 
                r[j+delta] = r[j];
            r[j+delta] = r[0];
        }
    }
}

void shell_sort (int r[], int l, int delta[], int n)
{
    int     i;
    for (i = 0; i < n; i++) {
        shell_insert (r, l, delta[i]);
    }
}

           時間複雜度:T(n) = O(n1.5)


     2.4  冒泡排序:第 i 趟對前前 n-i 個元素進行相鄰節點比較,若在某一趟中沒有發現一個逆序,則可以終止比較

             部分代碼(完整代碼bubble.c

#define SWAP(x, y, type) \
    {type    __swap_; \
     __swap_ = x; \
     x = y; \
     y = __swap_;}

void bubble_sort (int r[], int l)
{
    int     i, j; 
    int     t; 
    unsigned char   change = TRUE;

    for (i = 0; i < l && change; i++) {

        change = FALSE;
        for (j = 0; j < l-i-1; j++) 
            if (r[j] > r[j+1]) { 
                SWAP (r[j], r[j+1], int);
                change = TRUE;
            } 
     }
}


     2.5  快速排序:快排是對冒泡的一種改進,將軸從到輔助單元中,以軸爲中心從左右兩邊開始比較,如右邊碰到比軸小的則放到low裏邊,若左邊碰到比軸大的則放到hegh裏邊直到low >= high, 一趟結束,如此重複左邊和右邊的記錄

             部分代碼(完整代碼QKSort.c

void QK_sort (int r[], int low, int high)
{
    if (low < high) {
        int pos = QK_pass (r, low, high);
        QK_sort (r, low, pos-1);
        QK_sort (r, pos+1, high);
    }
}

int QK_pass (int r[], int low, int high)
{
    int x = r[low];

    while (low < high) {
        // 從右向左找小於x的元素
        while (low < high && r[high] >= x) 
            high--;
        // 找到小的送入low單元
        if (low < high) 
            r[low++] = r[high];

        // 從左向右找大於等於x的元素
        while (low < high && r[low] < x) 
            low++;
        // 找到大的送入high單元
        if (low < high) 
            r[high--] = r[low];
    }

    // 插入基準到 low = high單元
    r[low] = x;
    // 返回基準位置
    return low;
}


     2.6  選擇排序:在i+1到n這段記錄中找到小於i的且最小的和i進行交換,完成一趟,如此重複

             部分代碼(完整代碼selectSort.c

void select_sort (int r[], int n)
{
    int     i, j;

    for (i = 0; i < n; i++) { 
        int     k = i; 
        for (j = i+1; j < n; j++) {
            // 記錄k的位置,k是j到n-1小於i且最小的
            if (r[j] < r[k]) 
                k = j;

            // 如果有這樣的k則替換
            if (k != i)
                SWAP (r[i], r[k], int);
        }
    }
}

     2.6  堆排序排序:sift函數創建大根堆,然後在排序時將根和堆尾交換,堆尾移出,重建大根堆重複

             部分代碼(完整代碼heapSort.c

void sift (int r[], int k, int m)
{
    int t = r[k];
    int i = k;
    int j = 2*i;
    unsigned char   finished = FALSE;

    while (j <= m && !finished) {
        // 找到i的孩子中最大的孩子
        if (j < m && r[j] < r[j+1]) 
            j++;
        // 根比孩子都大,則結束
        if (t >= r[j]) 
            finished = TRUE;
        else {
            // 否則上移,繼續比較
            r[i] = r[j];
            i = j;
            j = 2*i;
        }
    }
    r[i] = t;
}

void crt_heap (int r[], int l)
{
    int i;
    for (i = l/2; i >= 1; i--)
        // 自第Ln/2」個記錄開始重建堆
        sift (r, i, l);
}

void heap_sort (int r[], int l)
{
    crt_heap (r, l);
    int i;

    for (i = l; i >= 2; i--) {
        // 存放堆尾
        int b = r[1];
        // 堆尾放到堆首
        r[1] = r[i];
        // 將b,將根存放到堆尾
        r[i] = b;
        // 重建堆
        sift (r, 1, i-1);
    }
}
</pre><pre code_snippet_id="254386" snippet_file_name="blog_20140325_8_8485226" name="code" class="plain">
發佈了65 篇原創文章 · 獲贊 9 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章