排序算法總結

排序算法

在這裏插入圖片描述

1 插入排序

1.1 直接插入排序

  • 最好情況下,O(n);最壞情況下O(n^2)
  • 原理:將一個長度爲n的數組分爲兩個集合:一個已排序集合和一個待排序集合,開始時已排序集合長度爲空(或者直接將待排序集合的第一張放入到已排序集合中),然後從待排序集合中拿出一個數字,和已排序集合中的數組進行比較,插入合適的位置。(可以想象爲兩堆撲克牌
#include<vector>
using namespace std;
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
#include "catch.hpp"

vector<int>& insertSort(vector<int> &v) {
    int len = v.size();
    if (len == 0 || len == 1)
        return v;
    for (int i = 1; i<len; ++i) {
        int insertNum = v[i];
        //尋找插入的位�?
        int j = i;
        while (j>0 && insertNum<v[j - 1]) {
            v[j] = v[j - 1];
            j--;
        }
        v[j] = insertNum;
    }
    return v;
}



SCENARIO("直接插入排序", "[vector]") {

    GIVEN("some vectors with some items") {
        std::vector<int> v1{};
        WHEN("size of vector is 0") {
            vector<int> sortedRes1{};
            THEN("test insertSort") {
                REQUIRE(v1.size() == 0);
                REQUIRE(insertSort(v1) == sortedRes1);
            }
        }

        std::vector<int> v2{ 1 };
        WHEN("size of vector is 1") {
            vector<int> sortedRes2{ 1 };
            THEN("test insertSort") {
                REQUIRE(v2.size() == 1);
                REQUIRE(insertSort(v2) == sortedRes2);
            }
        }

        std::vector<int> v3{ 5,4,3,2,1,0 };
        WHEN("size of vector is 6") {
            vector<int> sortedRes3{ 0,1,2,3,4,5 };
            THEN("test insertSort") {
                REQUIRE(v3.size() == 6);
                REQUIRE(insertSort(v3) == sortedRes3);
            }
        }

        std::vector<int> v4{ 9,23,52,3,0,2 };
        WHEN("size of vector is 6") {
            vector<int> sortedRes4{ 0,2,3,9,23,52 };
            THEN("test insertSort") {
                REQUIRE(v4.size() == 6);
                REQUIRE(insertSort(v4) == sortedRes4);
            }
        }
    }
}

1.2 二分插入排序

  • 最壞情況下,O(nlogn)
  • 原理:將直接插入排序的插入合適位置的那部分算法用折半查找法替換
#include<vector>
using namespace std;
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
#include "catch.hpp"

vector<int>& binaryInsertSort(vector<int> &v) {
    int len = v.size();
    if (len == 0 || len == 1)
        return v;
    for (int i = 1; i<len; ++i) {
        int insertNum = v[i];
        //尋找插入的位置
        int left=0, right=i-1;
        while (left<=right) {
            int middle = (left+right) / 2;
            if(insertNum < v[middle])
                right = middle-1;
            else
                left = middle + 1;
        }
        //插入待排序元素到已排序集合中
        for(int j=i; j>left; --j)
            v[j] = v[j-1];
        v[left] = insertNum;
    }
    return v;
}



SCENARIO("二分插入排序", "[vector]") {

    GIVEN("some vectors with some items") {
        vector<int> v1{};
        WHEN("size of vector is 0") {
            vector<int> sortedRes1{};
            THEN("test insertSort") {
                REQUIRE(v1.size() == 0);
                REQUIRE(binaryInsertSort(v1) == sortedRes1);
            }
        }

        vector<int> v2{ 1 };
        WHEN("size of vector is 1") {
            vector<int> sortedRes2{ 1 };
            THEN("test insertSort") {
                REQUIRE(v2.size() == 1);
                REQUIRE(binaryInsertSort(v2) == sortedRes2);
            }
        }

        vector<int> v3{ 5,4,3,2,1,0 };
        WHEN("size of vector is 6") {
            vector<int> sortedRes3{ 0,1,2,3,4,5 };
            THEN("test insertSort") {
                REQUIRE(v3.size() == 6);
                REQUIRE(binaryInsertSort(v3) == sortedRes3);
            }
        }

        vector<int> v4{ 9,23,52,3,0,2 };
        WHEN("size of vector is 6") {
            vector<int> sortedRes4{ 0,2,3,9,23,52 };
            THEN("test insertSort") {
                REQUIRE(v4.size() == 6);
                REQUIRE(binaryInsertSort(v4) == sortedRes4);
            }
        }
    }
}


1.3 希爾插入排序

  • 原理:將數組分爲gap=(n/2)組(這裏也可以取n/3),這樣每組就有n/gap個元素,對每一組進行插入排序,然後再將數組分爲gap /= 2,這樣每組的元素個數增多了,但是他們相對變得更有序了,然後再次執行插入排序,直到gap=0。
#include<vector>
using namespace std;
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
#include "catch.hpp"

vector<int>& shellInsertSort(vector<int> &v) {
    int len = v.size();
    if (len == 0 || len == 1)
        return v;

    int gap = len/2;
    while(gap) {
        for(int i=gap; i<len; ++i){
            int insertNum = v[i];
            int j = i;
            while(j>=gap && insertNum< v[j-gap]){
                v[j] = v[j-gap];
                j -= gap;
            }
            v[j] = insertNum;
        }
        gap /= 2;
    }
    return v;
}



SCENARIO("希爾插入排序", "[vector]") {

    GIVEN("some vectors with some items") {
        vector<int> v1{};
        WHEN("size of vector is 0") {
            vector<int> sortedRes1{};
            THEN("test insertSort") {
                REQUIRE(v1.size() == 0);
                REQUIRE(shellInsertSort(v1) == sortedRes1);
            }
        }

        vector<int> v2{ 1 };
        WHEN("size of vector is 1") {
            vector<int> sortedRes2{ 1 };
            THEN("test insertSort") {
                REQUIRE(v2.size() == 1);
                REQUIRE(shellInsertSort(v2) == sortedRes2);
            }
        }

        vector<int> v3{ 5,4,3,2,1,0 };
        WHEN("size of vector is 6") {
            vector<int> sortedRes3{ 0,1,2,3,4,5 };
            THEN("test insertSort") {
                REQUIRE(v3.size() == 6);
                REQUIRE(shellInsertSort(v3) == sortedRes3);
            }
        }

        vector<int> v4{ 9,23,52,3,0,2 };
        WHEN("size of vector is 6") {
            vector<int> sortedRes4{ 0,2,3,9,23,52 };
            THEN("test insertSort") {
                REQUIRE(v4.size() == 6);
                REQUIRE(shellInsertSort(v4) == sortedRes4);
            }
        }
    }
}


2 交換排序

2.1 冒泡排序

  • 最壞情況,O(n^2),最壞情況下比較的次數爲:n(n1)/2n*(n-1)/2,相應的對象移動的次數爲3/2n(n-1)
  • 原理:在一組數據中,相鄰元素依次比較大小,最大的放後面,最小的冒上來
#include<vector>
using namespace std;
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
#include "catch.hpp"

vector<int>& bubble(vector<int> &v) {
    int len = v.size();
    //進行len-1次冒泡,所有元素均已排好序
    for(int i=0; i<len-1; ++i){
        //在剩下的len-1-i次 冒泡中,從頭開始相鄰元素進行比較,最後最大的元素沉到最底下
        for(int j=0; j<len-1-i; ++j)
            if( v[j] > v[j+1])
            //交換相鄰元素
                swap(v[j], v[j+1]);
    }
    return v;
}



SCENARIO("冒泡排序", "[vector]") {

    GIVEN("some vectors with some items") {
        vector<int> v1{};
        WHEN("size of vector is 0") {
            vector<int> sortedRes1{};
            THEN("test insertSort") {
                REQUIRE(v1.size() == 0);
                REQUIRE(bubble(v1) == sortedRes1);
            }
        }

        vector<int> v2{ 1 };
        WHEN("size of vector is 1") {
            vector<int> sortedRes2{ 1 };
            THEN("test insertSort") {
                REQUIRE(v2.size() == 1);
                REQUIRE(bubble(v2) == sortedRes2);
            }
        }

        vector<int> v3{ 5,4,3,2,1,0 };
        WHEN("size of vector is 6") {
            vector<int> sortedRes3{ 0,1,2,3,4,5 };
            THEN("test insertSort") {
                REQUIRE(v3.size() == 6);
                REQUIRE(bubble(v3) == sortedRes3);
            }
        }

        vector<int> v4{ 9,23,52,3,0,2 };
        WHEN("size of vector is 6") {
            vector<int> sortedRes4{ 0,2,3,9,23,52 };
            THEN("test insertSort") {
                REQUIRE(v4.size() == 6);
                REQUIRE(bubble(v4) == sortedRes4);
            }
        }
    }
}


2.2 雞尾酒排序

  • 最壞和平均情況,O(n^2),最壞情況下比較的次數爲:n(n1)/2n*(n-1)/2
  • 最好情況,O(n)
  • 原理:每次遍歷有兩個方向,從左向右將最大的元素沉入最底下,從右向左將最小的元素浮上最表面
    https://blog.csdn.net/zhouzi2018/article/details/80394168
    在這裏插入圖片描述
#include<vector>
using namespace std;
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
#include "catch.hpp"

vector<int>& shaker(vector<int> &v) {
 int len = v.size();
 int left=0, right=len-1;
 while(left < right){
  //從左向右,將最大元素放入最後面
  for (int i = left; i < right; ++i)
   if (v[i] > v[i + 1])
    swap(v[i], v[i + 1]);
  right--;
  
  //從右向左,將最小元素放到最前面
  for(int i=right; i>left; --i)
   if(v[i]<v[i-1])
    swap(v[i], v[i-1]);
  left++;
 }
 return v;
}



SCENARIO("雞尾酒排序", "[vector]") {

    GIVEN("some vectors with some items") {
        vector<int> v1{};
        WHEN("size of vector is 0") {
            vector<int> sortedRes1{};
            THEN("test insertSort") {
                REQUIRE(v1.size() == 0);
                REQUIRE(shaker(v1) == sortedRes1);
            }
        }

        vector<int> v2{ 1 };
        WHEN("size of vector is 1") {
            vector<int> sortedRes2{ 1 };
            THEN("test insertSort") {
                REQUIRE(v2.size() == 1);
                REQUIRE(shaker(v2) == sortedRes2);
            }
        }

        vector<int> v3{ 5,4,3,2,1,0 };
        WHEN("size of vector is 6") {
            vector<int> sortedRes3{ 0,1,2,3,4,5 };
            THEN("test insertSort") {
                REQUIRE(v3.size() == 6);
                REQUIRE(shaker(v3) == sortedRes3);
            }
        }

        vector<int> v4{ 9,23,52,3,0,2 };
        WHEN("size of vector is 6") {
            vector<int> sortedRes4{ 0,2,3,9,23,52 };
            THEN("test insertSort") {
                REQUIRE(v4.size() == 6);
                REQUIRE(shaker(v4) == sortedRes4);
            }
        }
    }
}

2.3 快速排序

  • 平均複雜度,O(nlogn)
  • 最壞情況,O(n^2),比較次數:n2/2n^2/2
  • 最好情況下的空間複雜度:O(nlogn)
  • 最大遞歸調用層數:O(log(n+1))
  • 原理:使用分治和遞歸的思想。在數組中隨機選擇一個數作爲基準(這裏演示將第一個數作爲基準),然後將數組以此基準劃分爲左右兩個子序列:左側子序列的所有元素比基準小,右側子序列的所有元素都大於或等於基準。然後分別再對兩個子序列進行這樣的劃分處理,直到子序列爲空或排序完成。
#include<vector>

using namespace std;
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
#include "catch.hpp"

void quickSort(vector<int> &v, int left, int right) {
    //當輸入數組爲空或者只有一個元素時,不做處理,直接返回
    if(left == right)
        return ;
    int i=left, j=right;
    //選擇最左邊的元素爲基數
    int pivot = v[left];
    while(i<j){
        while(i<j && v[j]>=pivot)   j--;    //找到比基數小的元素,如果它還在最左邊元素的右邊,就交換它與最左邊元素值,把它作爲基數
        if(i<j)
            swap(v[i], v[j]);
        
        while(i<j && v[i]<=pivot)   i++;    //找到比基數大的元素,如果它還在基數的左邊,就交換它與基數, 把它作爲基數
        if(i<j)
            swap(v[i], v[j]);
    }
    if(i != left)   
        quickSort(v, left, i-1);    //對v[left...i-1]排序
    if(j != right)
        quickSort(v, j+1, right);   //對v[j+1...right]排序
    
}


// int main()
// {
//     vector<int> a{8,2,6,12,1,9,5,5,10};
//     int i;
//     quickSort(a,0,8);/*排好序的結果*/
    
//     for(i=0;i<8;i++)
//         printf("%4d",a[i]);
//     getchar();
//     return 0;
// }

SCENARIO("排序", "[vector]") {

    GIVEN("some vectors with some items") {
        vector<int> v1{};
        WHEN("size of vector is 0") {
            vector<int> sortedRes1{};
            THEN("test insertSort") {
                REQUIRE(v1.size() == 0);
                quickSort(v1, -1, -1);//這裏-1表示輸入數組爲空
                REQUIRE( v1 == sortedRes1);
            }
        }

        vector<int> v2{ 1 };
        WHEN("size of vector is 1") {
            vector<int> sortedRes2{ 1 };
            THEN("test insertSort") {
                REQUIRE(v2.size() == 1);
                quickSort(v2, 0, 0);
                REQUIRE( v2 == sortedRes2);
            }
        }

        vector<int> v3{ 5,4,3,2,1,0 };
        WHEN("size of vector is 6") {
            vector<int> sortedRes3{ 0,1,2,3,4,5 };
            THEN("test insertSort") {
                REQUIRE(v3.size() == 6);
                quickSort(v3, 0, 5);
                REQUIRE( v3 == sortedRes3);
            }
        }

        vector<int> v4{ 9,23,52,3,0,2 };
        WHEN("size of vector is 6") {
            vector<int> sortedRes4{ 0,2,3,9,23,52 };
            THEN("test insertSort") {
                REQUIRE(v4.size() == 6);
                quickSort(v4, 0, 5);
                REQUIRE( v4 == sortedRes4);
            }
        }

        vector<int> v5{ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
        WHEN("size of vector is 11") {
            vector<int> sortedRes5{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
            THEN("test insertSort") {
                REQUIRE(v5.size() == 11);
                quickSort(v5, 0, 10);
                REQUIRE( v5 == sortedRes5);
            }
        }
    }
}


3 選擇排序

3.1 直接選擇排序

  • 最壞情況,O(n^2)
  • 原理:每次從數組v[0],…v[len-1]中找到最小的元素v[k],然後與v[i]交換位置
#include<vector>
using namespace std;
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
#include "catch.hpp"

vector<int>& directSlecetSort(vector<int> &v) {
    int len = v.size();
    for(int i=0; i<len; ++i){
        int k = i;//暫時選擇第i個元素爲當前最小值
        //尋找最小的元素
        for(int j=i+1; j<len; ++j)
            if( v[j] < v[k]) k=j;
        //交換v[i]與最小值v[k]
        swap(v[i], v[k]);
    }
    return v;
}



SCENARIO("直接選擇排序", "[vector]") {

    GIVEN("some vectors with some items") {
        vector<int> v1{};
        WHEN("size of vector is 0") {
            vector<int> sortedRes1{};
            THEN("test insertSort") {
                REQUIRE(v1.size() == 0);
                REQUIRE(directSlecetSort(v1) == sortedRes1);
            }
        }

        vector<int> v2{ 1 };
        WHEN("size of vector is 1") {
            vector<int> sortedRes2{ 1 };
            THEN("test insertSort") {
                REQUIRE(v2.size() == 1);
                REQUIRE(directSlecetSort(v2) == sortedRes2);
            }
        }

        vector<int> v3{ 5,4,3,2,1,0 };
        WHEN("size of vector is 6") {
            vector<int> sortedRes3{ 0,1,2,3,4,5 };
            THEN("test insertSort") {
                REQUIRE(v3.size() == 6);
                REQUIRE(directSlecetSort(v3) == sortedRes3);
            }
        }

        vector<int> v4{ 9,23,52,3,0,2 };
        WHEN("size of vector is 6") {
            vector<int> sortedRes4{ 0,2,3,9,23,52 };
            THEN("test insertSort") {
                REQUIRE(v4.size() == 6);
                REQUIRE(directSlecetSort(v4) == sortedRes4);
            }
        }
    }
}


4 歸併排序

  • 最壞情況,O(nlogn)
  • 原理:採用遞歸和分治思想。將一個數組遞歸地二分爲兩個子序列,然後分別對兩個進行排序,最後合併兩個排好序的子序列進行統一排序。
#include<vector>
using namespace std;
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
#include "catch.hpp"

void merge(vector<int> &A, int left, int mid, int right){
    vector<int> tmp = vector<int>(right-left+1);
    int i = left;
    int j= mid+1;
    int k=0;
    //比較兩個子序列的每一個元素,將較小的元素加入到臨時數組中,直到其中某個子序列爲空
    while(i <= mid && j <= right){
        if(A[i] <= A[j])
            tmp[k++] = A[i++];
        else
            tmp[k++] = A[j++];
    }
    //如果左邊子序列還剩下未合併的元素,則直接把該序列元素加入到臨時數組中
    while(i<=mid)
        tmp[k++] = A[i++];
    //如果右邊子序列還剩下未合併的元素,則直接把該序列元素加入到臨時數組中
    while(j<=right)
        tmp[k++] = A[j++];
    //將臨時數組中的元素賦值給A
    for(i=0; i<k; ++i)
        A[left+i] = tmp[i];

}

void mergeSort(vector<int> &v, int left, int right) {
    int len = v.size();
    if(len == 0 || left>=right) return ;
    int mid = (left+right) / 2;
    mergeSort(v, left, mid);    //遞歸排序v[left...mid]
    mergeSort(v, mid+1, right); //遞歸排序v[mid+1...right]
    merge(v, left, mid, right); //將兩個已排序好的子序列合併
}



SCENARIO("排序", "[vector]") {

    GIVEN("some vectors with some items") {
        vector<int> v1{};
        WHEN("size of vector is 0") {
            vector<int> sortedRes1{};
            THEN("test insertSort") {
                REQUIRE(v1.size() == 0);
                mergeSort(v1, -1, -1);//這裏-1表示輸入數組爲空
                REQUIRE( v1 == sortedRes1);
            }
        }

        vector<int> v2{ 1 };
        WHEN("size of vector is 1") {
            vector<int> sortedRes2{ 1 };
            THEN("test insertSort") {
                REQUIRE(v2.size() == 1);
                mergeSort(v2, 0, 0);
                REQUIRE( v2 == sortedRes2);
            }
        }

        vector<int> v3{ 5,4,3,2,1,0 };
        WHEN("size of vector is 6") {
            vector<int> sortedRes3{ 0,1,2,3,4,5 };
            THEN("test insertSort") {
                REQUIRE(v3.size() == 6);
                mergeSort(v3, 0, 5);
                REQUIRE( v3 == sortedRes3);
            }
        }

        vector<int> v4{ 9,23,52,3,0,2 };
        WHEN("size of vector is 6") {
            vector<int> sortedRes4{ 0,2,3,9,23,52 };
            THEN("test insertSort") {
                REQUIRE(v4.size() == 6);
                mergeSort(v4, 0, 5);
                REQUIRE( v4 == sortedRes4);
            }
        }

        vector<int> v5{ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
        WHEN("size of vector is 11") {
            vector<int> sortedRes5{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
            THEN("test insertSort") {
                REQUIRE(v5.size() == 11);
                mergeSort(v5, 0, 10);
                REQUIRE( v5 == sortedRes5);
            }
        }
    }
}

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