基礎(chǔ)排序(四)

希爾排序(Shell Sort)

算法思想:先將待排序表分割成若干個(gè)形如L[i, i+d, i+2d, ... , i+kd]的“特殊”子表,分別進(jìn)行插入排序,當(dāng)整個(gè)表中元素已呈“基本有序”時(shí),再對(duì)全體記錄進(jìn)行一次插入排序。

算法圖解:

希爾排序

注:圖片來自Lyndon的專欄,如若侵權(quán)請聯(lián)系本人刪除,謝謝!

基本代碼如下:

template<typename T>
void shellSort(T arr[], int n) {

    // Incremnet表示增量
    int i, j, Increment;
    T tmp;
    // 增量變化
    for (Increment = n / 2; Increment > 0; Increment /= 2) {
        // 在增量為某個(gè)值時(shí),進(jìn)行插入排序
        for (i = Increment; i < n; ++i) {
            tmp = arr[i];
            for (j = i; j >= Increment; j -= Increment) {
                if (tmp < arr[j - Increment])
                    arr[j] = arr[j - Increment];
                else
                    break;
            }
            arr[j] = tmp;
        }
    }
}

為了和選擇排序、插入排序、冒泡排序比較算法效率,故分別創(chuàng)建SelectionSort.h文件、InsertionSort.h和BubbleSort.h文件,并分別添加如下代碼:

// SelectionSort.h

#include <iostream>

using namespace std;

template<typename T>
void selectionSort(T arr[], int n) {
    for (int i = 0; i < n - 1; i++) {
        // 尋找[i, n)區(qū)間里的最小值
        int minIndex = i;
        for (int j = i + 1; j < n; j++) {
            if (arr[j] < arr[minIndex])
                minIndex = j;
        }
        if (minIndex != i)
            swap(arr[i], arr[minIndex]);
    }
}
// InsertionSort.h

#include <iostream>

using namespace std;

template<typename T>
void insertionSort(T arr[], int n) {

    for (int i = 1; i < n; i++) {
        // 尋找元素arr[i]合適的插入位置

        T e = arr[i];
        // j保存元素e應(yīng)該插入的位置
        int j;
        for (j = i; j > 0 && arr[j - 1] > e; j--) {
            arr[j] = arr[j - 1];
        }
        arr[j] = e;
    }
}
// BubbleSort.h

#include <iostream>

using namespace std;

template<typename T>
void bubbleSort(T arr[], int n) {

    for (int i = 0; i < n - 1; ++i) {
        // 表示本趟冒泡是否發(fā)生交換的標(biāo)志
        bool flag = false;
        for (int j = n - 1; j > i; --j) {
            if (arr[j - 1] > arr[j]) {
                swap(arr[j - 1], arr[j]);
                flag = true;
            }
        }
        // 本趟遍歷后沒有發(fā)生交換,說明已有序
        if (flag == false) return;
    }
}

好了,我們在main()中調(diào)用這幾個(gè)算法比較一下它們的性能,具體代碼如下:

int main(void) {

    int n = 10000;
    int *arr_1 = SortTestHelper::generateRandomArray(n, 0, n);
    int *arr_2 = SortTestHelper::copyIntArray(arr_1, n);
    int *arr_3 = SortTestHelper::copyIntArray(arr_1, n);
    int *arr_4 = SortTestHelper::copyIntArray(arr_1, n);

    SortTestHelper::testSort("Shell Sort", shellSort, arr_1, n);
    SortTestHelper::testSort("Insertion Sort", insertionSort, arr_2, n);
    SortTestHelper::testSort("Selection Sort", selectionSort, arr_3, n);
    SortTestHelper::testSort("Bubble Sort", bubbleSort, arr_4, n);

    delete[] arr_1;
    delete[] arr_2;
    delete[] arr_3;
    delete[] arr_4;
    return 0;
}

其運(yùn)行結(jié)果如下:

Shell Sort : 0.003 s
Insertion Sort : 0.124 s
Selection Sort : 0.187 s
Bubble Sort : 0.866 s

從結(jié)果中,我們發(fā)現(xiàn)希爾排序在隨機(jī)數(shù)組的情況下,其運(yùn)行效率比之前我們學(xué)習(xí)的排序算法的效率都高。那么我們不禁想問希爾排序在處理近乎有序的數(shù)據(jù)時(shí),其效率也會(huì)這么高嗎?為此,我們調(diào)用generateNearlyOrderdArray()來測試一下,其代碼如下:

int main(void) {

    int n = 10000;
    int *arr_1 = SortTestHelper::generateNearlyOrderdArray(n, 100);
    int *arr_2 = SortTestHelper::copyIntArray(arr_1, n);
    int *arr_3 = SortTestHelper::copyIntArray(arr_1, n);
    int *arr_4 = SortTestHelper::copyIntArray(arr_1, n);

    SortTestHelper::testSort("Shell Sort", shellSort, arr_1, n);
    SortTestHelper::testSort("Insertion Sort", insertionSort, arr_2, n);
    SortTestHelper::testSort("Selection Sort", selectionSort, arr_3, n);
    SortTestHelper::testSort("Bubble Sort", bubbleSort, arr_4, n);

    delete[] arr_1;
    delete[] arr_2;
    delete[] arr_3;
    delete[] arr_4;
    return 0;
}

其運(yùn)行結(jié)果如下:

Shell Sort : 0.002 s
Insertion Sort : 0.003 s
Selection Sort : 0.293 s
Bubble Sort : 0.344 s

從結(jié)果中,我們發(fā)現(xiàn)希爾排序在處理近乎有序的數(shù)據(jù)時(shí),仍然可以保證高效率。因此,我們在處理近乎有序的數(shù)據(jù)時(shí),不僅推薦使用插入排序,也推薦希爾排序。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 概述 排序有內(nèi)部排序和外部排序,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序,而外部排序是因排序的數(shù)據(jù)很大,一次不能容納全部...
    蟻前閱讀 5,308評(píng)論 0 52
  • 概述:排序有內(nèi)部排序和外部排序,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序,而外部排序是因排序的數(shù)據(jù)很大,一次不能容納全部...
    每天刷兩次牙閱讀 3,829評(píng)論 0 15
  • 1.插入排序—直接插入排序(Straight Insertion Sort) 基本思想: 將一個(gè)記錄插入到已排序好...
    依依玖玥閱讀 1,357評(píng)論 0 2
  • 排序的基本概念 在計(jì)算機(jī)程序開發(fā)過程中,經(jīng)常需要一組數(shù)據(jù)元素(或記錄)按某個(gè)關(guān)鍵字進(jìn)行排序,排序完成的序列可用于快...
    Jack921閱讀 1,575評(píng)論 1 4
  • 這幾天連續(xù)下雨,下班回家路上超堵,到學(xué)校接到女兒時(shí),已是放學(xué)后的一個(gè)多小時(shí)了。 沒時(shí)間買菜,來點(diǎn)簡單點(diǎn)的蛋炒飯,比...
    cilin閱讀 297評(píng)論 3 3

友情鏈接更多精彩內(nèi)容