排序算法总结

1 冒泡排序

1.1 原理

假设有未排序数列array, 元素个数为n, 那么开始遍历array, 将每一个元素a和其下一个元素b进行比较, 如果a>b, 那么交换两个元素, 这样遍历一遍之后, 可以保证数列最后一个元素是最大的, 但是最后一个元素的前n-1个元素的顺序不确定, 这样把前n-1个元素当作一个新序列, 进行上述遍历并交换, 使得第n -1个元素为第二大的元素, 这样遍历n遍之后可以使得数列有序.

1.2 代码实现

class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {
        int n = nums.size() - 1;
        while (n) {
            for (int i = 0; i < n; i ++) {
                if (nums[i] > nums[i + 1])
                    swap(nums[i], nums[i + 1]);
            }
            n --;
        }
        return nums;
    }
};

1.3 性能及内存

时间复杂度O(n^{2}), 最坏时间复杂度O(n^{2}), 最好时间复杂度O(n), 空间复杂度O(1), 稳定, 性能测试如图.

2 选择排序

2.1 原理

选择排序即为把整个序列分为已排序序列和未排序序列, 让序列号从0开始, 一直到序列末尾, 序列号(包括自身)之前代表着已排序序列, 序列号之后代表未排序序列, 从未排序序列中找到最小元素, 与当前序列号元素进行交换, 这样遍历到结尾, 整个序列即为有序序列.

2.2 代码实现

vector<int> sortArray(vector<int>& nums) {
    int n = nums.size();
    for (int i = 0; i < n; i ++) {
        int min_index = i;
        for (int j = i + 1; j < n; j ++) {
            if (nums[j] < nums[min_index]) {
                min_index = j;
            }
        }
        swap(nums[i], nums[min_index]);
    }
    return nums;
}

2.3 性能及内存

时间复杂度O(n^{2}), 最坏时间复杂度O(n^{2}), 最好时间复杂度O(n^{2}), 空间复杂度O(1), 不稳定, 性能测试如图:

3 插入排序

3.1 原理

在待排序序列中, 从左到右进行遍历, 每遍历一个元素, 把其向前插入到合适的位置, 这样保证每遍历一个元素时, 其前面的元素都是有序的. 至于插入到合适位置的具体方法, 就是每一次都和前面的元素比较, 如果大于前面的元素, 就和其交换.

3.2 代码实现

vector<int> sortArray(vector<int>& nums) {
    int n = nums.size();
    for (int i = 1; i < n; i ++) {
        for (int ii = i; ii > 0 && nums[ii] < nums[ii - 1]; ii --) {
            swap(nums[ii], nums[ii - 1]);
        }
    }
    return nums;
}

3.3 性能及内存

时间复杂度O(n^{2}), 最坏时间复杂度O(n^{2}), 最好时间复杂度O(n), 空间复杂度O(1), 不稳定, 性能测试如图:

4 希尔排序

5 归并排序

5.1 原理

把一个无序列表分为两个列表, 然后按照依次取出最小元素的方法合并成一个新的有序表(至于两个子表怎么排序, 可以用递归的方法).

5.2 代码实现

我写的比较笨:

void vectorMergeSort(vector<int> &unorderedVec, vector<int> &orderedVec) {
    if (unorderedVec.size() < 2) {
        orderedVec = unorderedVec;
        return;
    }
    vector<int> firstHalf(unorderedVec.begin(), unorderedVec.begin() + unorderedVec.size() / 2);
    vector<int> secondHalf(unorderedVec.begin() + unorderedVec.size() / 2, unorderedVec.end());
    vector<int> orderedFirstHalf;
    vector<int> orderedSecondHalf;
    vectorMergeSort(firstHalf, orderedFirstHalf);
    vectorMergeSort(secondHalf, orderedSecondHalf);
    auto orderedFirstHalfIter = orderedFirstHalf.begin();
    auto orderedSecondHalfIter = orderedSecondHalf.begin();
    while (orderedFirstHalfIter != orderedFirstHalf.end() &&
        orderedSecondHalfIter != orderedSecondHalf.end()) {
        if (*orderedFirstHalfIter < *orderedSecondHalfIter) {
            orderedVec.push_back(*orderedFirstHalfIter);
            orderedFirstHalfIter ++;
        } else {
            orderedVec.push_back(*orderedSecondHalfIter);
            orderedSecondHalfIter ++;
        }
    }
    if (orderedFirstHalfIter != orderedFirstHalf.end())
        orderedVec.insert(orderedVec.end(), orderedFirstHalfIter, orderedFirstHalf.end());
    if (orderedSecondHalfIter != orderedSecondHalf.end())
        orderedVec.insert(orderedVec.end(), orderedSecondHalfIter, orderedSecondHalf.end());

}

void mergeSort(int* array, int array_size){
    vector<int> arrayVec;
    for_each(array, array + array_size, [&](auto element){arrayVec.push_back(element);});
    vector<int> resVector;
    vectorMergeSort(arrayVec, resVector);
    int arrayIndex = 0;
    for_each(resVector.begin(),resVector.end(), [&](auto element){array[arrayIndex ++] = element;});
}

5.3 性能及内存

时间复杂度O(nlog_{2}n), 最坏时间复杂度O(nlog_{2}n), 最好时间复杂度O(nlog_{2}n), 空间复杂度O(n), 稳定, 性能测试如图:

6 快速排序

7 堆排序

8 计数排序

8.1 原理

计数排序就是用一个新的数组, 数组的索引就是每个元素的值, 存的值是每个元素在原数组出现了几次, 最后再通过遍历这个频率表, 再把原数组存回去.

8.2 代码

9 桶排序

10 基数排序

10.1 原理

基数排序只能对整数进行排序, 其原理是首先把数组的每个元素按照每一位从小到大进行排序, 直到遍历到最后一位. 这样对比桶排序的好处就是, 其用到的额外空间更小.

10.2 代码

void sortPosArray(vector<int>& nums) {
    if (nums.empty())
        return;
    //首先遍历找到最大的数
    int Max = nums[0];
    for (int num: nums) {
        Max = max(Max, num);
    }
    int util = 1;
    while (Max >= util) {
        //把nums的每个数按照当前的取位值放进buckets里面
        //取位运算: (num / util) % 10
        vector<vector<int>> buckets(10, vector<int>());
        for (int num: nums) {
            buckets[(num / util) % 10].push_back(num);
        }
        //nums清了
        nums.clear();
        //把buckets里面的数放回nums里面
        for (auto bucket: buckets) {
            for (int num: bucket) {
                nums.push_back(num);
            }
        }
        util *= 10;
    }
}
vector<int> sortArray(vector<int>& nums) {
    vector<int> pos_num;
    vector<int> neg_num;
    for(int num: nums) {
        if (num < 0) {
            neg_num.push_back(-num);
        } else {
            pos_num.push_back(num);
        }
    }
    sortPosArray(pos_num);
    sortPosArray(neg_num);
    int neg_n = neg_num.size();
    vector<int> new_neg;
    for (int i = neg_n - 1; i >= 0; i --) {
        new_neg.push_back(-neg_num[i]);
    }
    new_neg.insert(new_neg.end(), pos_num.begin(), pos_num.end());
    return new_neg;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值