排序算法总结

排序算法

在这里插入图片描述

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 ∗ ( n − 1 ) / 2 n*(n-1)/2 n(n1)/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 ∗ ( n − 1 ) / 2 n*(n-1)/2 n(n1)/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),比较次数: n 2 / 2 n^2/2 n2/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);
            }
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值