01-0003 C++諸多排序算法,前來報到~

前言:個人覺得在這些函數裏面註釋足夠詳細,不需要太多的解釋,適合有基礎的人看,主要是用來回憶算法細節,快速撿起該算法。其實是應爲我實在寫不動了,最近既要找工作,又要寫畢設,卻是有點忙不過來。而且源碼1000多行,寫註釋寫到吐的我也真的是醉了,甚至想扔出一隻只嚶嚶怪,然後開始一局嚶嚶怪忍者,emm~
.
它如同參考文檔,在未來的開發中起着指導性作用,但是不可直接拿來使用;在實際應用中可能比這個要複雜的多,需要進行更多的優化與改進。
.
如果想要更加詳細的掌握每一種排序算法,可以在點擊最下端的相關鏈接,都是我參考過的,也可以自行百度,拿着別人的算法與本算法進行比對,帶着這裏的註釋,去看懂別處的代碼。
.
如果想要直接運行可以點擊最下端的下載鏈接,上面有VS2019的工程文件,裏面寫的比較詳細,整體觀比較強,因目前還沒有上傳GitHub,CSDN現在不可以設置免費下載,所以見諒。
.
不過還是可以get到源文件的,可以✉給我寫信✉,或者是將下面的函數自己整理到對應的文件中,自己運行一下也是可以的。

.
在下面的代碼段中,對常見的部分莫過於數據的拷貝,memcpy函數的使用,why?

1.因爲本文實現了一個類,類中有多個排序方法,但是卻只有一組數據;
2.爲了方便測試,只能每次排序的時候都拷貝一份,而後返回有序數組;
3.同樣爲了方便測試,所有排序最後都可以通過一個無參函數進行調用。

Note:一定要把上面的文字看完,否則容易產生誤解。

P1:初始化部分 [initial part]

爲方便使用排序算法,設置了一個可以根據外部數據進行初始化的構造函數。
爲方便測試排序算法,設置了一顆可以自動生成待排數組的構造函數。

1.構造函數 [Constructed function]

/***************************************************
**名稱:Cpp_Sorts
**參數:data:給定數組,num:數組長度
**返回:無
**功能:根據指定的數組和長度對類對象進行初始化
**性能:
**注意:一定要初始化map
****************************************************/
Cpp_Sorts::Cpp_Sorts(int const* data, const int num) {
    this->data = new int[num];
    this->num = num;
    memcpy(this->data, data, sizeof(int) * num);//將傳入的數據,拷貝到this->data中
    ini_func();//記得初始化【字符串-函數名】map
}

/***************************************************
**名稱:Cpp_Sorts
**參數:left:隨機下限,right:隨機上限,num:生成隨機數的個數
**返回:無
**功能:根據上下限,生成num個隨機數,並初始化map
**性能:
**注意:初始化map
****************************************************/
Cpp_Sorts::Cpp_Sorts(int const left, int const right, int const num) {
    random_arr(left, right, num);
    ini_func();//記得初始化【字符串-函數名】map
}

2.隨機生成 [random create]

/***************************************************
**名稱:random_arr
**參數:begin:隨機下限,end:隨機上限,num:隨機數個數
**返回:無
**功能:根據上下限生成num個隨機數,並且給該類成員賦值
**性能:
**注意:data要申請空間
****************************************************/
void Cpp_Sorts::random_arr(int begin, int end, int num) {
    this->num = num;
    data = new int[this->num];
    srand((unsigned int)time(NULL));//初始化種子
    for (int i = 0; i < this->num; i++) {
        data[i] = rand() % (end - begin + 1) + begin;//成成[begin,end]的隨機數
    }
}

3.通過字符串調用成員函數 [call method by string]

/***************************************************
**名稱:ini_fun
**參數:無
**返回:無
**功能:初始化【字符串-函數名】的map
**性能:
**注意:注意下面的書寫格式,不能變
****************************************************/
void Cpp_Sorts::ini_func() {
    fun_map["select"] = &Cpp_Sorts::s_select;
    fun_map["insert"] = &Cpp_Sorts::s_insert;
    fun_map["quick"] = &Cpp_Sorts::s_quick;
    fun_map["heap"] = &Cpp_Sorts::s_heap;
    fun_map["std_sort"] = &Cpp_Sorts::s_sort;
    fun_map["std_stable_sort"] = &Cpp_Sorts::s_stable_sort;
    fun_map["bubble"] = &Cpp_Sorts::s_bubble;
    fun_map["cocktail"] = &Cpp_Sorts::s_cocktail;
    fun_map["shell"] = &Cpp_Sorts::s_shell;
    fun_map["botonic"] = &Cpp_Sorts::s_bitonic_rec;
    fun_map["merge"] = &Cpp_Sorts::s_merge;
    fun_map["LSD"] = &Cpp_Sorts::s_LSD;
    fun_map["MSD"] = &Cpp_Sorts::s_MSD;
    fun_map["gnome"] = &Cpp_Sorts::s_gnome;
    fun_map["bogo"] = &Cpp_Sorts::s_bogo;
}

/***************************************************
**名稱:use_function
**參數:fun_name:函數名字
**返回:無
**功能:根據函數名字,調用類的成員函數,並計算函數運行的時間
**性能:
**注意:調用之前一定要初始化
****************************************************/
void Cpp_Sorts::use_function(string fun_name) {
    cout << "Using sort: " << fun_name << endl;
    auto start = steady_clock::now();//時鐘開始
    int* arr = (this->*fun_map[fun_name])();
    auto end = steady_clock::now();//時鐘結束
    print_arr(arr);//打印數組
    auto dur = duration_cast<microseconds>(end - start);//計算間隔
    cout << "Time consumption: " << dur.count() << "μs" << endl;
}

P2:排序部分 [sort part]

1.選擇排序 [select sort]

描述:反覆從序列中選出極值元素放置在序列一段[已經選擇過的象徵性剔除]

  1. 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
  2. 再從剩餘未排序元素中繼續尋找最小(大)元素,然後放到已排序序列的末尾。
  3. 重複第二步,直到所有元素均排序完畢。
/***************************************************
**名稱:s_select
**參數:無
**返回:排好順序的數組的指針
**功能:統一接口,調用之後自動排序
**性能:
**注意:
****************************************************/
int* Cpp_Sorts::s_select() {
    return s_select(this->data, this->num);
}
/***************************************************
**名稱:s_select
**參數:data:原始數組,num:數組長度
**返回:指向有序數組的指針
**功能:拷貝一個data數組,並對數組元素進行排序
**性能:最好O(n^2),平均O(n^2),最壞O(n^2)
**注意:分兩段,兩重循環
****************************************************/
int* Cpp_Sorts::s_select(int const* data, const int num) {
    //拷貝副本
    int* arr = new int[num];
    memcpy(arr, data, sizeof(int) * num);

    //選擇排序
    //選擇一個最小的元素與第i個元素進行交換
    //小元素最後都放在前面,有序段越來越長
    //第一輪循環用於遍歷所有元素
    //這個代碼還是很好的懂的,你細品
    for (int min, i = 0; i < num - 1; i++) {
        min = i;
        //第二輪循環用來找最小元素的下標
        for (int j = i + 1; j < num; j++) {
            if (arr[min] > arr[j]) {
                min = j;
            }
        }
        //找到最小元素,進行交換
        if (min != i) {
            arr[min] ^= arr[i] ^= arr[min] ^= arr[i];
        }
    }
    return arr;
}

2.插入排序 [insert part]

描述:順序選擇序列中的元素插入到有序數據段中[象徵性的分割原始序列]

  1. 將排序序列第一個元素看做一個有序序列,把第二個元素到最後一個元素當成是未排序序列。
  2. 從頭到尾依次掃描未排序序列,將掃描到的每個元素插入有序序列的適當位置。(如果有相等則插入到相等元素的後面。[規則可以自己定義])
/***************************************************
**名稱:s_insert
**參數:無
**返回:有序數組的指針
**功能:
**性能:
**注意:
****************************************************/
int* Cpp_Sorts::s_insert() {
    return s_insert(this->data, this->num);
}
/***************************************************
**名稱:s_insert
**參數:data:原始數組,num:數組長度
**返回:有序數組的指針
**功能:拷貝原始數組,並對新數組排序返回
**性能:最好O(n),平均O(n^2),最壞O(n^2)
**注意:分兩段,兩重循環
****************************************************/
int* Cpp_Sorts::s_insert(int const* data, const int num) {
    //拷貝副本
    int* arr = new int[num];
    memcpy(arr, data, sizeof(int) * num);

    //插入排序
    //插入排序前段有序,後端無序
    //每次從後段裏面取出一個,從後向前對前段元素進行比較,到合適位置進行插入
    //第一輪循環用於遍歷尾部未知元素
    for (int i = 1; i < num; i++) {
        int temp = arr[i];
        int j = i - 1;
        //第二輪循環用於挪動前段有序元素,給待插入元素騰位置
        //如果有序段全都挪動了位置,說明這個元素最小
        //如果找到一個元素比當前元素小,就把當前元素緊隨其後放置
        //意即,找到一個不比temp大的元素,將temp放在該元素的後面
        while ((j >= 0) && (arr[j] > temp)) {
            arr[j + 1] = arr[j];//有序段元素相逐漸後撤
            j--;
        }
        //如果有序段發生了變化
        if (j != i - 1) {
            arr[j + 1] = temp;
        }
    }
    return arr;
}

3.快速排序 [quick sort]

描述:置元素於選定的基準兩側,逐步遞歸

  1. 從數列中挑出一個元素,稱爲 “基準”(pivot);
  2. 重新排序數列,所有元素比基準值小的擺放在基準前面,所有元素比基準值大的擺在基準的後面(相同的數可以到任一邊)。
  3. 遞歸地(recursive)把小於基準值元素的子數列和大於基準值元素的子數列排序;
/***************************************************
**名稱:s_quick
**參數:無
**返回:指向有序數數組的指針
**功能:統一接口
**性能:
**注意:
****************************************************/
int* Cpp_Sorts::s_quick() {
    return s_quick(this->data, this->num);
}
/***************************************************
**名稱:s_quick
**參數:data:原始數組,num:數組長度
**返回:指向有序數組的指針
**功能:調用重載的s_quick函數
**性能:
**注意:high索引值
****************************************************/
int* Cpp_Sorts::s_quick(int const* data, const int num) {
    //拷貝副本
    //由於快排要改變當前數組,所以在遞歸前進行拷貝
    int* arr = new int[num];
    memcpy(arr, data, sizeof(int) * num);
    return s_quick(arr, 0, num - 1);//確保高端元素的索引不超出範圍
}
/***************************************************
**名稱:s_quick
**參數:arr:待排序數組,low:左端,high:右端
**返回:返回有序數組的指針
**功能:對數組進行排序,並返回指向該數組的指針
**性能:最好:O(nlogn),平均O(nlogn),最壞:O(n^2)
**注意:下標別弄混
****************************************************/
int* Cpp_Sorts::s_quick(int* arr, int const low, int const high) {
    if (high <= low) return arr;//當匯聚到中間的時候退出
    int i = low, j = high + 1, key = arr[low];//默認第一個元素是key,下面是--j,所以這裏寫的是j=high+1
    while (true) {
        while (arr[++i] < key && (i != high));  //從左向右找比key大的值
        while (arr[--j] > key && (j != low));   //從右向左找比key小的值
        if (i >= j) break;
        arr[i] ^= arr[j] ^= arr[i] ^= arr[j];   //交換i,j對應的值,交換之後j位置的值是比low小的
    }
    if (low < j)//確保使用異或進行數值交換的是兩個不一樣的值
        arr[low] ^= arr[j] ^= arr[low] ^= arr[j];//中樞值與j對應值交換,去報中數值在中間
    s_quick(arr, low, j - 1);
    s_quick(arr, j + 1, high);
}

4.堆排序 [heap sort]

描述:建立二叉堆並反覆摘取最大元

  1. 創建一個堆 H[0……n-1];
  2. 把堆首(最大值)和堆尾互換;
  3. 把堆的尺寸縮小 1,並調用 shift_down(0),目的是把新的數組頂端數據調整到相應位置;
  4. 重複步驟 2,直到堆的尺寸爲 1
/***************************************************
**名稱:s_heap
**參數:無
**返回:指向有序數組的指針
**功能:
**性能:
**注意:
****************************************************/
int* Cpp_Sorts::s_heap() {
    return s_heap(this->data, this->num);
}
/***************************************************
**名稱:s_heap
**參數:data:原始數組,num:數組長度
**返回:指向有序數組的指針
**功能:堆排序
**性能:最好=平均=最壞=O(nlogn)
**注意:
****************************************************/
int* Cpp_Sorts::s_heap(int const* data, int const num) {
    //拷貝副本
    int* arr = new int[num];
    memcpy(arr, data, sizeof(int) * num);

    //排序
    //神奇的是,調整的過程與建立大根堆的過程是一致的
    //建立大根堆
    for (int i = num / 2 - 1; i >= 0; i--) {
        //注意這裏是從最後一個根節點開始的,可以自己代入試一試,確實是最後一個節點
        s_max_heapify(arr, i, num - 1);//實際上的建立大根堆過程,最後一個節點的計算公式準確無誤
    }
    //每次浮上一個最小元素,沉下一個最大元素
    for (int i = num - 1; i > 0; i--) {
        arr[0] ^= arr[i] ^= arr[0] ^= arr[i];//交換首尾兩個元素的位置
        s_max_heapify(arr, 0, i - 1);//末尾少去一個元素之後,再進行調整
    }
    return arr;
}
/***************************************************
**名稱:s_max_heapify
**參數:arr:待排序數組,start:數組首位,end:數組末位
**返回:指向具有堆序性的數組的指針
**功能:見於函數內部
**性能:
**注意:
****************************************************/
int* Cpp_Sorts::s_max_heapify(int* arr, int const start, int const end) {
    //兩個功能:
    //1、對於任意三個元素(one dad,two sons)進行大根堆調整
    //2、當大根堆建立完畢之後,讓小元素下沉,大元素上升。
    //【由於大根堆已經建立完畢,所以能浮在上層的一定是大元素,而且不會有比他更大的,而小元素則會繼續下沉,直到一個合適的位置】
    int dad = start;
    int son = dad * 2 + 1;
    while (son <= end) {
        if (son + 1 <= end && arr[son] < arr[son + 1])//從子節點中選擇一個比較大的,並且標記下標
            son++;
        if (arr[dad] > arr[son])//如果父節點更大,就直接返回
            return arr;
        else {//否則就應該將父子節點交換,讓大的在上面
            arr[dad] ^= arr[son] ^= arr[dad] ^= arr[son];
            dad = son;//然後更加深入讓小元素沉到海底
            son = dad * 2 + 1;
        }
    }
}

5.標準庫:sort [STL:sort]

描述:標準庫函數,sort()排序不是穩定排序,sort是主要用到了快速排序(平均時間複雜度爲O(nlogn)),還結合了插入排序(時間複雜度爲O(n²))和堆排序(時間複雜度爲O(nlogn))

/***************************************************
**名稱:s_sort
**參數:無
**返回:指向有序數組的指針
**功能:
**性能:
**注意:
****************************************************/
int* Cpp_Sorts::s_sort() {
    return s_sort(this->data, this->num);
}
/***************************************************
**名稱:s_sort
**參數:data:原始數組,num:元素個數
**返回:指向有序數組的指針
**功能:拷貝,排序,返回指針
**性能:平均O(nlogn)
**注意:這裏使用的是標準庫函數
****************************************************/
int* Cpp_Sorts::s_sort(int const* data, int const num) {
    //創建副本
    int* arr = new int[num];
    memcpy(arr, data, sizeof(int) * num);

    //排序
    /*int*beg=std::begin(arr);//begin()可以直接對於數組元素使用,但是不能動態數組使用
    int* end = end(arr);*/
    //對數組使用迭代器的方式,尾部並不是最後一個元素,而是最後一個元素後的一個空元素
    std::sort(&arr[0], &arr[num]);
    return arr;
}

6.標準庫:stable_sort [STL:stable_sort]

描述:標準庫函數,保證最壞的排序效率。

/***************************************************
**名稱:s_stable_sort
**參數:無
**返回:指向有序數組的指針
**功能:
**性能:
**注意:
****************************************************/
int* Cpp_Sorts::s_stable_sort() {
    return s_sort(this->data, this->num);
}
/***************************************************
**名稱:s_stable_sort
**參數:data:原始數組,num:元素個數
**返回:指向有序數組的指針
**功能:拷貝,排序,返回指針
**性能:最壞:O(n(logn)^2),保證最壞情況
**注意:標準庫函數,穩定排序
****************************************************/
int* Cpp_Sorts::s_stable_sort(int const* data, int const num) {
    //創建副本
    int* arr = new int[num];
    memcpy(arr, data, sizeof(int) * num);

    //排序
    /*int*beg=std::begin(arr);//begin()可以直接對於數組元素使用,但是不能動態數組使用
    int* end = end(arr);*/
    //對數組使用迭代器的方式,尾部並不是最後一個元素,而是最後一個元素後的一個空元素
    std::stable_sort(&arr[0], &arr[num]);
    return arr;
}

7.冒泡排序 [bubble sort]

描述:兩兩比較選擇大者依次排列在最後[設定判定標誌]

  1. 比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。
  2. 對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。這步做完後,最後的元素會是最大的數。
  3. 針對所有的元素重複以上的步驟,除了最後一個。
  4. 持續每次對越來越少的元素重複上面的步驟,直到沒有任何一對數字需要比較。
/***************************************************
**名稱:s_bubble
**參數:無
**返回:指向有序數組的指針
**功能:
**性能:
**注意:
****************************************************/
int* Cpp_Sorts::s_bubble() {
    return s_bubble(this->data, this->num);
}
/***************************************************
**名稱:s_bubble
**參數:data:原始數組,num:數組長度
**返回:指向有序數組的指針
**功能:拷貝,排序,返回指針
**性能:最好:O(n)[改進之後],平均:O(n^2),最壞:O(n^2)
**注意:可以添加標記位,標記是否需要排序。[一般都是需要的]
**注意:數據少的時候性能還是不錯的
****************************************************/
int* Cpp_Sorts::s_bubble(int const* data, int const num) {
    int* arr = new int[num];
    memcpy(arr, data, sizeof(int) * num);

    //sort
    //冒泡排序需要兩次循環
    //第一重循環用來縮減前段待排序列
    //第二循環用來將大元素交換到最後
    //version_1,習慣使用版本一,方便書寫。
    for (int i = 0; i < num - 1; i++)
        for (int j = 0; j < num - 1 - i; j++)
            if (arr[j] > arr[j + 1])
                arr[j] ^= arr[j + 1] ^= arr[j] ^= arr[j + 1];
    //version_2
    /*bool exchange;//設置標記位,是否發生了交換
    for (int i = 0; i < num - 1; i++) {
        exchange = false;
        for (int j = 0; j < num - 1 - i; j++) {
            if (arr[j] > arr[j + 1]) {
                arr[j] ^= arr[j + 1] ^= arr[j] ^= arr[j + 1];
                exchange = true;
            }
        }
        if (!exchange) break;//如果沒有發生交換,就直接退出
    }*/
    return arr;
}

8.雞尾酒排序 [cocktail sort]

描述:相鄰元素成對比較,確定大小兩值置於兩端

  1. 比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。
  2. 對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。在這一點,最後的元素應該會是最大的數。
  3. 針對所有的元素重複以上的步驟,除了最後一個。
  4. 持續每次對越來越少的元素重複上面的步驟,直到沒有任何一對數字需要比較。
/***************************************************
**名稱:s_cocktail
**參數:無
**返回:指向有序數組的指針
**功能:
**性能:
**注意:
****************************************************/
int* Cpp_Sorts::s_cocktail() {
    return s_cocktail(this->data, this->num);
}
/***************************************************
**名稱:s_cocktail
**參數:data:原始數組,num:數組長度
**返回:指向有序數組的指針
**功能:拷貝,排序,返回
**性能:最好:O(n),平均:O(n^2),最壞:O(n^2)
**注意:
****************************************************/
int* Cpp_Sorts::s_cocktail(int const* data, int const num) {
    //實質上是一個雙向的冒泡排序
    int* arr = new int[num];
    memcpy(arr, data, sizeof(int) * num);

    //sort
    //1.先從左到右,兩兩進行對比,將大的元素浮動到最右側,記錄下右邊界
    //2.再從右到左,兩兩進行對比,將小的元素浮動到最左側,記錄下左邊界
    //3.直到某次不發生交換,就返回
    int left = 0, bounder = 0, right = num - 1;//標記邊界的bound是必須的,不能直接使用right or left
    bool swepped = true;//如果沒有發生過交換,可以直接返回
    while (swepped) {
        swepped = false;
        for (int i = left; i < right; i++) {
            if (arr[i] > arr[i + 1]) {
                arr[i] ^= arr[i + 1] ^= arr[i] ^= arr[i + 1];
                swepped = true;
                bounder = i;//每次標記右邊界,bounder現在剛好是小元素的位置
            }
        }
        right = bounder;//更新右邊界,這裏都是剛好的,不用進行加減等麻煩的操作

        for (int i = right; i > left; i--) {
            if (arr[i] < arr[i - 1]) {
                arr[i] ^= arr[i - 1] ^= arr[i] ^= arr[i - 1];
                swepped = true;
                bounder = i;//每次標記左邊界,bounder現在剛好是大元素的位置
            }
        }
        left = bounder;//更新左邊界
    }
    return arr;
}

9.地精排序 [gnome sort]

描述:設置標識,前進冒泡一次後折返,循環到達元素末尾時終止

  1. 只有一層循環,默認情況下前進冒泡
  2. 一旦遇到冒泡的情況發生就往回冒,直到把這個數字放好爲止
/***************************************************
**名稱:s_gnome
**參數:無
**返回:指向有序數組的指針
**功能:
**性能:
**注意:
****************************************************/
int* Cpp_Sorts::s_gnome() {
    return s_gnome(this->data, this->num);
}
/***************************************************
**名稱:s_gnome
**參數:data:原始數組,num:數組長度
**返回:指向有序數組的指針
**功能:拷貝,排序,返回指針
**性能:最好:O(n),平均:O(n^2),最壞O(n^2)
**注意:
****************************************************/
int* Cpp_Sorts::s_gnome(int const* data, int const num) {
    int* arr = new int[num];
    memcpy(arr, data, sizeof(int) * num);

    //gnome
    //1.順序向後,兩兩對比,直到遇見更小的元素
    //2.從該元素開始往回冒泡,直到將其放到正確的位置
    //3.再從該位置向後走,如遇類似情形就重複1/2操作
    int i = 0;//沒有必要在語法上進行縮減,而應還從算法上進行精化
    while (i < num) {
        if (i == 0 || arr[i - 1] <= arr[i]) {
            i++;//用於退出的量,只要是向右走,就要進行加·1
        }
        else {
            arr[i - 1] ^= arr[i] ^= arr[i - 1] ^= arr[i];
            i--;//向左走的就要減1
        }
    }
    return arr;
}

10.希爾排序 [shell sort]

描述:視作二維矩陣逐步壓縮行高

  1. 選擇一個增量序列 t1,t2,……,tk,前者大於後者,tk = 1;[可以反過來定義,算法需要修改]
  2. 按增量序列個數 k,對序列進行 k 趟排序;
  3. 每趟排序,根據對應的增量 ti,將待排序列分割成若干長度爲 m 的子序列,分別對各子表進行直接插入排序。
  4. 僅增量因子爲 1 時,整個序列作爲一個表來處理,表長度即爲整個序列的長度。
/***************************************************
**名稱:s_shell
**參數:無
**返回:指向有序元素的指針
**功能:隨機使用兩種不同的希爾排序
**性能:
**注意:
****************************************************/
int* Cpp_Sorts::s_shell() {
    srand(time(0));
    if (rand() % 2 == 0)
        return s_shell_1(this->data, this->num);
    else
        return s_shell(this->data, this->num);
}
/***************************************************
**名稱:s_shell
**參數:data:原始數組,num:數組長度
**返回:指向有序數組的指針
**功能:進行希爾排序
**性能:平均:O(n^(7/6)),最壞:O(n^(4/3)),[斐波那契數列]:O(n^(3/2))
**注意:有一部分人會自己規定gap序列Wie斐波那契數列,似乎是效率比較好
****************************************************/
int* Cpp_Sorts::s_shell(int const* data, int const num) {
    int* arr = new int[num];
    memcpy(arr, data, sizeof(int) * num);

    //shell_sort
    //每一次gap都變爲原來的1/2
    //loop-1:控制gap變小
    for (int gap = num / 2; gap > 0; gap /= 2) {
        //loop-2:控制插入排序的第一輪循環
        for (int i = gap; i < num; i++) {
            int j = i;//控制組
            //也算是插入排序,基於交換的
            //也有點像是冒泡排序,不過這個是向前的
            //可以理解爲向前冒泡,或者是不完整的插入排序
            //loop-3:控制插入排序
            while (j - gap >= 0 && arr[j] < arr[j - gap]) {
                arr[j] ^= arr[j - gap] ^= arr[j] ^= arr[j - gap];
                j -= gap;
            }
        }
    }
    return arr;
}
/***************************************************
**名稱:s_shell
**參數:data:原始數組,num:數組長度
**返回:指向有序數組的指針
**功能:進行希爾排序
**性能:平均:O(n^(7/6)),最壞:O(n^(4/3)),[斐波那契數列]:O(n^(3/2))
**注意:有一部分人會自己規定gap序列Wie斐波那契數列,似乎是效率比較好
****************************************************/
int* Cpp_Sorts::s_shell_1(int const* data, int const num) {
    int* arr = new int[num];
    memcpy(arr, data, sizeof(int) * num);

    //shell sort: version-1
    //大致流程與上面都是一樣的
    int gap = 1;
    while (gap < num / 3)
        gap = gap * 3 + 1;
    while (gap >= 1) {//上一種方法這裏是for循環,用的是while循環,gap>0等效於gap>=1
        for (int i = gap; i < num; i++) {
            //上面用的是while循環進行的插入排序
            //這裏使用的是for循環進行插入排序
            //多一種寫法,看着比較牛逼,其實是一個道理
            for (int j = i; j >= gap && arr[j] < arr[j - gap]; j -= gap) {
                arr[j] ^= arr[j - gap] ^= arr[j] ^= arr[j - gap];
            }
        }
        gap /= 3;
    }
    return arr;
}

11.雙調排序【非遞歸】 [bitonic sort]

描述:[可以並行,效率會大大的提高。只能處理2^n個數的數據]

/***************************************************
**名稱:s_bitonic
**參數:無
**返回:指向有序數組的指針
**功能:
**性能:
**注意:
****************************************************/
int* Cpp_Sorts::s_bitonic() {
    return s_bitonic(this->data, this->num);
}
/***************************************************
**名稱:s_bitonic
**參數:data:原始數組,num:數組長度
**返回:指向有序數組的指針
**功能:進行非遞歸的雙調排序
**性能:平均:O(n(logn)^2)[串行]  
**注意:雙調排序可以串行處理,在多機器的情況下效率是很高的
****************************************************/
int* Cpp_Sorts::s_bitonic(int const* data, int const num) {
    int* arr = new int[num];
    memcpy(arr, data, sizeof(int) * num);

    bool up = true;
    //將普通的無序序列轉化爲雙調序列
    for (int step = 2; step < num; step *= 2) {
        for (int i = 0; i < num; i += 2 * step) {
            //事實上這兩處的順序並不重要,只要滿足雙調序列的定義即可
            //雙調數列的構建過程:
            //2(1),4(2,1),8(4,2,1),16(8,4,2,1)
            //括號裏面每次都是需要逐漸深入的
            //代碼需要時常觀摩
            s_bitonic(arr + i, step, up);//前半段遞增
            s_bitonic(arr + step + i, step, !up);//後半段遞減
        }
    }
    return s_bitonic(arr, num, up);//對雙調序列進行排序,而後返回
}
/***************************************************
**名稱:s_bitonic
**參數:arr:數組,num:元素個數,up:是否遞增
**返回:滿足雙調序列定義的數組,或有序數組
**功能:1.構建雙調序列 2.對於雙調序列進行排序
**性能:
**注意:雙調序列概念
****************************************************/
int* Cpp_Sorts::s_bitonic(int* arr, int const num, bool up) {
    //bitonic_sort
    //默認升序排列
    //可以對照參考鏈接仔細理解這裏的
    //構建雙調序列的時候,這裏的num是逐漸擴倍的
    for (int step = num / 2; step > 0; step /= 2) {//步長縮減
        for (int i = 0; i < num; i += 2 * step) {//第i組元素
            for (int j = 0; j < step; j++) {//第i組元素與第i+1組元素的比較
                if (up) {//是否是增序
                    if (arr[i + j] > arr[i + j + step])//前者大,則與後者換位
                        arr[i + j] ^= arr[i + step + j] ^= arr[i + j] ^= arr[i + step + j];
                }
                else {//如果是降序
                    if (arr[i + j] < arr[i + j + step])//前者小,則與後者換位
                        arr[i + j] ^= arr[i + step + j] ^= arr[i + j] ^= arr[i + step + j];
                }
            }
        }
    }
    return arr;
}

12.雙調排序【遞歸】 [recursive bitonic sort]

/***************************************************
**名稱:s_bitonic_rec
**參數:無
**返回:指向有序數組的指針
**功能:統一接口
**性能:
**注意:
****************************************************/
int* Cpp_Sorts::s_bitonic_rec() {
    return s_bitonic_rec(this->data, this->num);
}
/***************************************************
**名稱:s_bitonic_rec
**參數:data:原始數組,num:元素個數
**返回:指向有序數組的指針
**功能:次級接口
**性能:
**注意:先進行數據拷貝
****************************************************/
int* Cpp_Sorts::s_bitonic_rec(int const* data, int const num) {
    int* arr = new int[num];
    memcpy(arr, data, sizeof(int) * num);

    bool up = true;//升序
    return s_bitonic_rec(arr, num, up);//調用雙調排序
}
/***************************************************
**名稱:s_bitonic_get_len
**參數:len:長度
**返回:參與雙調排序的數據長度
**功能:找一個2的次冪,讓它剛好比len小
**性能:
**注意:任何數字都可以拆成多2的冪級表達式的和(etc:15=2^3+2^2+2^1+2^0)
****************************************************/
int Cpp_Sorts::s_bitonic_get_len(int const len) {
    int k = 1;
    while (k < len) k = k << 1;//滿足條件,擴大兩倍
    return k >> 1;//上面循環最後一次運行,多擴大了一次,這裏應該除下來
}
/***************************************************
**名稱:s_bitonic_rec
**參數:arr:數組,len:元素個數,up:是否增序
**返回:指向有序數組的指針
**功能:遞歸雙調排序
**性能:平均:O(n(logn)^2)[串行]  
**注意:前半段降序,後半段升序
****************************************************/
int* Cpp_Sorts::s_bitonic_rec(int* arr, int const len, bool up) {
    if (len > 1) {
        int m = len / 2;
        //以下的強制順序與遞歸的流程是有關係的
        //將整個流程走一遍,如果最後要求的是增序,在遞歸情況下爲滿足雙調序列的定義,必須先降後增
        //如果最後要求的是降序排列,這裏同樣也需要先降後增
        //改變了順序,程序就會輸出錯誤的結果
        //之前非遞歸版本的不要求這樣做,原因未知
        s_bitonic_rec(arr, m, !up);//前半段降序,遞歸要求一定要這麼做,why?
        s_bitonic_rec(arr + m, len - m, up);//後半段升序
        //回收並不是所有的遞歸都結束之後才運行的
        //從最後一次不符合條件的遞歸開始,這個歸併機制就已經開始起作用了
        //最深層的遞歸,逐漸向上調用這個歸併機制
        s_bitonic_rec_merge(arr, len, up);//歸併機制
    }
    return arr;
}
/***************************************************
**名稱:s_bitonic_rec_merge
**參數:arr:數組,len:元素個數,up:是否增序
**返回:無
**功能:對於任意雙調序列進行歸併
**性能:
**注意:
****************************************************/
void Cpp_Sorts::s_bitonic_rec_merge(int* arr, int const len, bool up) {
    //任意雙調排序的歸併
    //此函數即能用來生成雙調函數,也能用來歸併,非常的經典
    if (len > 1) {
        int m = s_bitonic_get_len(len);//前半段的長度
        for (int i = 0; i < len - m; i++) {//源碼中寫的額是++i,其實並不影響,for循環中第一次使用的是初始化的0
            if (arr[i] > arr[i + m] == up)//如果是升序,會對交換兩者,如果是降序,後者大,也需要對兩者進行交換
                arr[i] ^= arr[i + m] ^= arr[i] ^= arr[i + m];//上面的判斷條件很將就
        }
        s_bitonic_rec_merge(arr, m, up);//對於前半段遞增歸併,或者是遞減,與下面的保持一致
        s_bitonic_rec_merge(arr + m, len - m, up);//對於後半段也遞增,或者是遞減
    }
}

13.猴子排序 [bogo sort]

描述:隨緣吧!

/***************************************************
**名稱:s_bogo
**參數:無
**返回:指向有序元素的指針
**功能:統一入口
**性能:
**注意:
****************************************************/
int* Cpp_Sorts::s_bogo() {
    return s_bogo(this->data, this->num);
}
/***************************************************
**名稱:s_get_dif_m_shu
**參數:index:遞增數組,num:元素個數
**返回:指向打亂順序的數組的指針
**功能:打亂遞增數組的元素順序
**性能:
**注意:
****************************************************/
int* Cpp_Sorts::s_get_dif_m_shu(int* index, int const num) {
    std::random_device rd;
    std::mt19937 g(rd());
    shuffle(&index[0], &index[num], g);
    return index;
}
/***************************************************
**名稱:s_bogo_is_order
**參數:arr:數組,index:下標數組,num:元素個數
**返回:是否有序bool類型值
**功能:根據index數組,判斷arr數組中的元素是否有序
**性能:
**注意:
****************************************************/
bool Cpp_Sorts::s_bogo_is_order(int const* arr, int const* index, int const num) {
    //比如,arr[3,5,1,2],index[2,3,0,1]
    //將index中的元素作爲arr的索引,可以有arr[2]<arr[3]<arr[0]<arr[1]
    //此時,根據index數組判斷arr數組的元素是有序的
    for (int i = 1; i < num; i++) {
        if (arr[index[i]] < arr[index[i - 1]])
            return false;
    }
    return true;
}
/***************************************************
**名稱:s_bogo——print
**參數:arr:數組,num:元素個數
**返回:無
**功能:打印
**性能:
**注意:就是想簡單的輸出一下,調試的時候使用的
****************************************************/
void Cpp_Sorts::s_bogo_print(int const* arr, int num) {
    for (int i = 0; i < num; i++)
        cout << arr[i] << ' ';
    cout << endl;
}
/***************************************************
**名稱:s_bogo
**參數:data:數組,num:元素個數
**返回:指向有序數組的指針
**功能:模擬猴子按鍵的過程,每次不同的鍵位,看這些鍵位是否有序
**性能:極差
**注意:元素個數>10的時候不建議使用
****************************************************/
int* Cpp_Sorts::s_bogo(int const* data, int const num) {
    int* arr = new int[num];
    memcpy(arr, data, sizeof(int) * num);

    int* index = new int[num];//不知道這一部分空間應該在哪裏刪除掉
    iota(&index[0], &index[num], 0);//對數組進行遞增的初始化,從0開始,每次+1
    index = s_get_dif_m_shu(index, num);//打亂下標數組中的元素
    while (!s_bogo_is_order(arr, index, num)) {//判斷是否有序
        index = s_get_dif_m_shu(index, num);//若無序,就繼續打亂
        //s_bogo_print(index, num);//打印猴子按鍵的過程
    }
    arr = s_bogo(data, index, num);
    return arr;
}
/***************************************************
**名稱:s_bogo
**參數:arr:數組,index:下標數組,num:元素個數
**返回:指向有序數組的指針
**功能:根據index中的下標依次取arr中的元素,並回放index數組中
**性能:
**注意:這裏取巧,讓index數組充當了有序數組容器,並將其返回
****************************************************/
int* Cpp_Sorts::s_bogo(int const* arr, int* index, int const num) {
    for (int i = 0; i < num; i++) {
        index[i] = arr[index[i]];
    }
    return index;
}

14.歸併排序 [merge sort]

這裏需要一個非遞歸的版本,下次寫好了之後添加上。

描述:2048[遞歸和迭代兩個版本]

  1. 申請空間,使其大小爲兩個已經排序序列之和,該空間用來存放合併後的序列;
  2. 設定兩個指針,最初位置分別爲兩個已經排序序列的起始位置;
  3. 比較兩個指針所指向的元素,選擇相對小的元素放入到合併空間,並移動指針到下一位置;
  4. 重複步驟 3 直到某一指針達到序列尾;
  5. 將另一序列剩下的所有元素直接複製到合併序列尾。
/***************************************************
**名稱:s_merge_m
**參數:arr:數組,left:左下標,right:右下標,mid:中間下標
**返回:無
**功能:對於[left,right]之間的元素分兩部分進行歸併
**性能:
**注意:
****************************************************/
void Cpp_Sorts::s_merge_m(int* arr, int const left, int const right, int const mid) {
    int* temp = new int[right - left + 1];
    int i = 0, p1 = left, p2 = mid + 1;
    //取小的先放
    while (p1 <= mid && p2 <= right) {
        temp[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
    }
    //第一部分沒放完的放置在後面
    while (p1 <= mid) {
        temp[i++] = arr[p1++];
    }
    //第二部分沒放完的繼續向後放
    while (p2 <= right) {
        temp[i++] = arr[p2++];
    }
    //將歸併好的部分,拷貝給原來的數組
    memcpy(arr + left, temp, sizeof(int) * (right - left + 1));
    delete[] temp;//清除申請的內存
}
/***************************************************
**名稱:s_merge_rec
**參數:arr:數組,left:左下標,right:右下標
**返回:無
**功能:遞歸進行歸併排序
**性能:最好:O(nlogn),平均:O(nlogn),最壞:O(nlogn)
**注意:遞歸的兩部分不要重複
****************************************************/
void Cpp_Sorts::s_merge_rec(int* arr, int const left, int const right) {
    if (left == right) return;
    int mid = (left + right) / 2;
    //思想是很簡單的,但實際上這是一個遞歸的過程
    s_merge_rec(arr, left, mid);//對於左邊遞歸
    s_merge_rec(arr, mid + 1, right);//對於右邊進行遞歸,一定要+1確保不會重複
    s_merge_m(arr, left, right, mid);//如果兩邊都好了,就開始進行合併
}
/***************************************************
**名稱:s_merge
**參數:data:原始數據,num:元素個數
**返回:指向有序數組的指針
**功能:調用歸併排序
**性能:
**注意:
****************************************************/
int* Cpp_Sorts::s_merge(int const* data, int const num) {
    int* arr = new int[num];
    memcpy(arr, data, sizeof(int) * num);
    s_merge_rec(arr, 0, num - 1);
    return arr;
}
/***************************************************
**名稱:s_merge
**參數:無
**返回:指向有序數組的指針
**功能:統一入口
**性能:
**注意:
****************************************************/
int* Cpp_Sorts::s_merge() {
    return s_merge(this->data, this->num);
}

15.LSD排序 [LSD sort]

描述:最低位優先批次進行排序,最後讀取序列

  1. 首先根據個位數的數值,在走訪數值時將它們分配至編號0到9的桶子中:
  2. 接着再進行一次分配,這次是根據十位數來分配:
  3. 接下來將這些桶子中的數值重新串接起來,成爲以下的數列:
  4. [位數變多則多進行幾步]
/***************************************************
**名稱:s_LSD
**參數:無
**返回:指向有序數組的指針
**功能:
**性能:
**注意:
****************************************************/
int* Cpp_Sorts::s_LSD() {
    return s_LSD(this->data, this->num);
}
/***************************************************
**名稱:s_LSD
**參數:data:數組,num:元素個數
**返回:指向有序數組的指針
**功能:使用LSD對數組進行排序
**性能:最好:O(d(n+rd)),平均:O(d(n+r)),最壞:O(d(n+r))
**注意:
****************************************************/
int* Cpp_Sorts::s_LSD(int const* data, int const num) {
    int* arr = new int[num];
    memcpy(arr, data, sizeof(int) * num);
    int digit = s_LSD_get_d(arr, num);  //獲取最高位的位數
    queue<int>* p_queue[10];            //指向隊列的數組,指針數組,有10個queue<int>的指針,相當於算法中的十個桶
    for (int i = 0; i < 10; i++) {      //同時需要進行初始化
        p_queue[i] = new queue<int>;
    }

    int* temp = new int[num];           //出桶的時候臨時存儲數據
    for (int d = 1; d <= digit; d++) {  //每一位都要進行比較
        //入桶
        for (int i = 0; i < num; i++) { //進行一趟個位的排序,根據第n位進行入桶
            p_queue[arr[i] / (int)pow(10, d - 1) % 10]->push(arr[i]);
        }
        //出桶
        for (int i = 0, count = 0; i < 10; i++) {
            while (!p_queue[i]->empty())
            {
                temp[count++] = p_queue[i]->front();    //獲取第一個元素
                p_queue[i]->pop();                      //第一個元素出隊列
            }
        }
        //交換兩個指針
        int* temp_2;
        temp_2 = arr;
        arr = temp;//保證每一次的arr都是經過排列的
        temp = temp_2;
    }
    delete[] temp;//清空臨時指針指向的空間
    return arr;
}
/***************************************************
**名稱:s_LSD_get_d
**參數:arr:數組,num:元素個數
**返回:數組中最大元素的位數
**功能:求數組中最大元素的位數
**性能:
**注意:同下面的s_MSD_get_d
****************************************************/
int Cpp_Sorts::s_LSD_get_d(int const* arr, int const num) {
    int max = arr[0];
    int digit = 1;
    for (int i = 1; i < num; i++) {
        if (arr[i] > max)
            max = arr[i];
    }
    while (max /= 10) {
        ++digit;
    }
    return digit;
}

16.MSD排序 [MSD sort]

描述:高位分桶,桶內遞歸

  1. 先根據最高位關鍵碼K1排序,得到若干對象組,對象組中每個對象都有相同關鍵碼K1。
  2. 再分別對每組中對象根據關鍵碼K2進行排序,按K2值的不同,再分成若干個更小的子組,每個子組中的對象具有相同的K1和K2值。
  3. 依此重複,直到對關鍵碼Kd完成排序爲止。
  4. 最後,把所有子組中的對象依次連接起來,就得到一個有序的對象序列。
/***************************************************
**名稱:s_MSD
**參數:無
**返回:指向有序數組的指針
**功能:隨機使用一種s_MSD算法
**性能:
**注意:不同的初始化方式
****************************************************/
int* Cpp_Sorts::s_MSD() {
    //隨機使用一下兩種中的一種
    //數據拷貝,有序s_MSD算法使用遞歸,會對數據自身進行調整,因此需要在這裏進行數據拷貝
    int* arr = new int[this->num];
    memcpy(arr, this->data, sizeof(int) * this->num);

    int digit = s_LSD_get_d(arr, this->num);//獲取最大數字的位數
    srand(time(0));
    int x = rand() % 2;
    x = 10;
    if (x == 0) {
        int* arr_back = new int[this->num];
        int count = 0;
        s_MSD(arr, this->num, digit, arr_back, count);
        return arr_back;
    }
    else {
        vector<int> A(arr, arr + num);//初始化一個向量
        s_MSD(A, digit);
        for (int i = 0; i < num; i++) {//排序結束之後將向量中的元素放入數組之中並且返回
            arr[i] = A[i];
        }
        return arr;
    }
}
/***************************************************
**名稱:s_MSD
**參數:arr:數組,num:數組元素個數,digit:位數,arr_back:用於回收的數組,count:用於記錄回收了幾個元素
**返回:無
**功能:對arr進行遞歸的MSD算法,將回收的元素放入arr_back數組之中並返回
**性能:最好:O(d(n+rd)),平均:O(d(n+r))[r爲基數,d爲位數][n是放一趟的次數,r爲收集一趟的次數],最壞:O(d(n+r))
**備註:關於性能的描述並不是特別懂
**注意:count一定要傳引用,內存的清理
****************************************************/
void Cpp_Sorts::s_MSD(int* arr, int const num, int const digit, int* arr_back, int& count) {
    //最終的元素應該如何收集
    //這裏的遞歸不太會使用
    //自己寫的版本,不能使用arr自身進行數據的回收
    //要麼使用vector<vector<int>>,要麼使用二維數組,都可以正確使用arr自身進行數據的回收
    queue<int>* p_queue[10];            //十個桶
    for (int i = 0; i < 10; i++)        //對這十個桶進行初始化
        p_queue[i] = new queue<int>;

    for (int i = 0; i < num; i++)       //按照最高位入桶
        p_queue[arr[i] / (int)pow(10, digit - 1) % 10]->push(arr[i]);

    for (int i = 0; i < 10; i++) {      //對於十個桶進行遍歷
        int size = p_queue[i]->size();
        if (size == 1) {                //如果size等於1說明這個桶裏面只有一個元素,直接放入arr_back中即可
            arr_back[count++] = p_queue[i]->front();//回收
        }
        else if (size > 1) {
            int* arr_b = new int[size]; //新的待排序的數組,將現在這個桶裏的元素放入其中
            for (int j = 0; j < size; j++) {
                arr_b[j] = p_queue[i]->front();
                p_queue[i]->pop();
            }
            s_MSD(arr_b, size, digit - 1, arr_back, count);//對於元素個數大於1的桶進行遞歸
            delete[] arr_b;             //清空之前arr_b申請的空間,清理內存
        }
    }
}
/***************************************************
**名稱:s_MSD
**參數:vec:待排序向量,digit:最大元素的位數
**返回:無
**功能:對vec向量遞歸排序
**性能:最好:O(d(n+rd)),平均:O(d(n+r))[r爲基數,d爲位數][n是放一趟的次數,r爲收集一趟的次數],最壞:O(d(n+r))
**注意:推薦這種算法,比較精妙
****************************************************/
void Cpp_Sorts::s_MSD(vector<int>& vec, int digit) {
    int len = vec.size();
    vector<vector<int>> p_vector(10);//聲明10個桶,並進行初始化

    if (digit >= 1 && len > 1) {//如果位數不爲0,而且桶中的元素個數大於1個
        for (int i = 0; i < len; i++)//對於桶中的元素進行分配
            p_vector[vec[i] / (int)pow(10, digit - 1) % 10].push_back(vec[i]);

        for (int i = 0, j = 0; i < 10; i++) {
            //遞歸進行排序
            s_MSD(p_vector[i], digit - 1);//上面判斷過桶中元素個數是否>1,這裏如果不滿足,就會跳出該輪遞歸,進行下面的語句
            //加入之前有一個桶中的元素是(23,24,21),經過分配之後會變成{(21),(23),(24)}
            //然後對這三個元素調用s_MSD,都會被阻斷,然後進入下面的回收機制中
            //vec是原來有三個元素的桶,經過分配之後它已經爲空,p_vector[i]每一個桶
            //21,23,24會依次進入原來的vec桶中,它大小未變,但vec中的元素已經有序
            //當前vec所處的桶序列回收結束之後,又會進入上一級遞歸
            while (!p_vector[i].empty()) {//單次回收的時候都是對的
                vec[j++] = p_vector[i].front();
                p_vector[i].erase(p_vector[i].begin());//回收一個元素,釋放一個元素
            }
        }
    }
}
/***************************************************
**名稱:s_MSD_get_d
**參數:arr:數組,num:元素個數
**返回:數組中最大元素的位數
**功能:求數組中最大元素的位數
**性能:
**注意:
****************************************************/
int Cpp_Sorts::s_MSD_get_d(int const* arr, int const num) {
    int max = arr[0];
    int digit = 1;
    for (int i = 1; i < num; i++) {//找出最大元素
        if (arr[i] > max)
            max = arr[i];
    }
    while (max /= 10) {//除10不爲零,說明有了有了一位
        ++digit;//鑑於while循環的先判斷性質,滿足條件就直接先加上
    }
    return digit;
}

P3:相關鏈接 [relative link]

1.參考鏈接 [reference link]

1.C++ 隨機生成區間範圍內的隨機數
2.標準庫頭文件 <algorithm>
3.標準庫頭文件 <numeric>
4.C++11標準庫chrono庫使用
5.基於C++11 chrono庫的計時器
6.How to call a function by its name (std::string) in C++?
7.c++ 成員函數指針
8.error C3867:非標準語法;請使用“&”來創建指向成員的指針
9.error C3867:非標準語法;請使用“&”來創建指向成員的指針
10.c++基礎之vector、數組初始化
11.【排序算法】基數排序:LSD 與 MSD
12.基數排序(LSD+MSD)詳解
13.const 和 非const函數重載
14.C++ 求冪的運算符是什麼?
15.c++中的運算符優先級
16.怎樣快速提取一個數字中的每一位數
17.c++指針可以指向棧嗎?
18.指針數組和數組指針的區別
19.C++ 標準庫中的堆(heap)
20.分治法之歸併排序三種實現方法(遞歸、非遞歸和自然合併排序)
21.基數排序(LSD)
22.十大經典排序算法(動圖演示)
23.[圖解] 歸併排序
24.C++ iota()函數
25.std::shuffle-c++
26.C++ 11中的隨機排列函數shuffle
27.網易有道編程題:洗牌算法(C++)
28.猴子排序法的實際意義?
29.排序算法——猴子排序(Bogosort)【代碼實現】
30.Java排序 - 不實用的幾個排序算法 – 睡眠排序、猴子排序、麪條排序、珠排序
31.C++洗牌算法
32.棧的應用:棧混洗
33.棧混洗的概念
34.VS中展開和摺疊代碼,還有其他快捷操作
35.三十分鐘理解:雙調排序Bitonic Sort,適合並行計算的排序算法
36.【並行計算】Bitonic Sort(雙調排序)基礎
37.雙調排序
38.五分鐘學會一個高難度算法:希爾排序
39.指針常量和常量指針

2.參考文檔 [reference doc]

1.cppreference.com
2.c++ reference oschina
3.cplusplus.com
4.c++ 中文手冊 51yip
5.遊戲蠻牛C++手冊
6.C++ 教程 runoob
7.C++ References
8.C++ Tutorial w3schools
9.C++ Tutorial geeksforgeeks

3.在線編譯 [online editor]

推薦使用前十個,最後一個,多數都不用上外網,前兩個是菜鳥教程上的,【4】很簡潔,【6】沒有用過,似乎能建立工程,界面簡單而且沒有廣告。

1.runoob.com
2.w3cschool.cn
3.godbolt.org
4.cpp.sh
5.ideone.com
6.winfengtech.com
7.c++ 代碼測試
8.tool.lu/coderunner
9.wandbox.org
10.onlinegdb.com
11.jdoodle.com
12.tutorialspoint.com
13.codechef.com
14.codiva.io
15.geeksforgeeks
16.coliru
其他:
1.程序員專用十大在線編譯器(IDE)整理
2.List of Online C++ Compilers

4.相關論壇 [relative forums]

1.https://isocpp.org/
2.CSDN C++論壇
3.stack overflow
4.綜合型編程論壇
5.吾愛破解 - 編程語言區

5.給我寫信 [write e-mail]

郵箱:[email protected]
寫信地址:✉✉✉✉

6.下載資源 [download code]

下載:Cpp_Sort.zip

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章