排序学习笔记

排序

平均最好最坏稳定性额外空间类型
O ( n 2 ) O(n^2) O(n2) O ( n 2 ) O(n^2) O(n2) O ( n 2 ) O(n^2) O(n2) O ( 1 ) O(1) O(1)选择
O ( n 2 ) O(n^2) O(n2) O ( n ) O(n) O(n) O ( n 2 ) O(n^2) O(n2) O ( 1 ) O(1) O(1)冒泡
O ( n 2 ) O(n^2) O(n2) O ( n ) O(n) O(n) O ( n 2 ) O(n^2) O(n2) O ( 1 ) O(1) O(1)插入
O ( n log ⁡ ( n ) ) O(n\log(n)) O(nlog(n)) O ( n log ⁡ ( n ) ) O(n\log(n)) O(nlog(n)) O ( n log ⁡ ( n ) ) O(n\log(n)) O(nlog(n)) O ( 1 ) O(1) O(1)
O ( n log ⁡ ( n ) ) O(n\log(n)) O(nlog(n)) O ( n log ⁡ ( n ) ) O(n\log(n)) O(nlog(n)) O ( n 2 ) O(n^2) O(n2) O ( 1 ) O(1) O(1)快速
O ( n log ⁡ ( n ) ) O(n\log(n)) O(nlog(n)) O ( n log ⁡ ( n ) ) O(n\log(n)) O(nlog(n)) O ( n log ⁡ ( n ) ) O(n\log(n)) O(nlog(n)) O ( n ) O(n) O(n)归并
O ( n log ⁡ ( n ) ) = O ( n + k ) O(n\log(n))=O(n+k) O(nlog(n))=O(n+k) O ( n + k ) O(n+k) O(n+k) O ( n + k ) O(n+k) O(n+k) O ( n + k ) O(n+k) O(n+k)计数
O ( n log ⁡ ( n ) ) = O ( n + k ) O(n\log(n))=O(n+k) O(nlog(n))=O(n+k) O ( n 2 ) O(n^2) O(n2) O ( n ) O(n) O(n) O ( n + k ) O(n+k) O(n+k)
O ( n ⋅ k ) O(n \cdot k) O(nk) O ( n ⋅ k ) O(n \cdot k) O(nk) O ( n ⋅ k ) O(n \cdot k) O(nk) O ( n + k ) O(n + k) O(n+k)基数
O ( n 1.3 ) O(n^{1.3}) O(n1.3) O ( n ) O(n) O(n) O ( n 2 ) O(n^2) O(n2) O ( 1 ) O(1) O(1)希尔

选择、冒泡、插入

选择

vector<int> selectionSort(vector<int>& nums) {
    int n = nums.size();
    for (int i = 0; i < n; i++){
        int min_idx=i;
        int min_val = nums[i];
        for (int j = i+1; j < n; j++){
            if (nums[j]<min_val){
                min_idx = j;
                min_val=nums[j];
            }
        }
        swap(nums[i], nums[min_idx]);  // 导致不稳定
    }
    return nums;
}

冒泡

vector<int> bubbleSort(vector<int>& nums) {
    int n = nums.size();
    bool sorted = false;  // 终止指示
    for (int i = 0; i < n; i++){  // 记录有序元素个数
    	sorted = true;
        for (int j = 0; j < n-i-1; j++){
            if (nums[j]>nums[j+1]){
                swap(nums[j], nums[j+1]);  // 可以使用tmp存储,在合适时插入
                sorted = false;
            }
        }
        if (sorted) break;
    }
    return nums;
}

插入

 vector<int> insertionSort(vector<int>& nums) {
     int n = nums.size();
     for (int i = 1; i < n; i++){
         int cur = nums[i];
         int j = i-1;
         for(; j >= 0; --j){
             if (cur < nums[j]){
                 nums[j+1] = nums[j];
                 if (j==0) nums[j]=cur;
             }else{
                 nums[j+1] = cur;
                 break;
             }
         }
     }
     return nums;
 }

堆、快速、归并


需要构造优先级队列时,额外增加push_heap即可。元素添加到末尾,然后沿着父亲链上滤。

template<typename Iter>
inline void filter_down(Iter first, int total, int cur){
    while(true){
        auto cur_it = first+cur-1;
        int left_idx = total<cur*2?cur:cur*2;
        int right_idx = total<cur*2+1?cur:cur*2+1;
        auto left_child = first+left_idx-1;
        auto right_child = first+right_idx-1;
        int cur_val = *(first+cur-1);
        if (cur_val>=*left_child && cur_val>=*right_child){break;}
        int child_idx = *left_child>*right_child?cur*2:cur*2+1;
        auto larger_it = first+child_idx-1;
        swap(*larger_it, *cur_it);
        cur = child_idx;
    }
}
template<typename Iter>
void make_heap_(Iter first, Iter end){
    size_t total = distance(first, end);
    for(int idx = total; idx>0; idx--){
        filter_down(first, total, idx);
    }
}
template<typename Iter>
void pop_heap_(Iter first, Iter end){
    int total = distance(first, end)-1;
    swap(*first, *(end-1));
    filter_down(first, total, 1);
}
class Solution {
public:
    vector<int> heapSort(vector<int>& nums) {
        size_t n = nums.size();
        make_heap_(nums.begin(), nums.end());
        for (size_t i = 0; i < n; i++){
            pop_heap_(nums.begin(), nums.end()-i);
        }
        return nums;
    }
};

快速
原地排序。对于堆排序来说优点在于可并行,使用不同物理核心处理不同部分。缺点是最坏情况的复杂度较高,可能被黑客利用进行拒绝服务攻击。

class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {
        quickSort(nums, 0, nums.size()-1);
        return nums;
    }
    void quickSort(vector<int>&nums, int lo, int hi){
        if (lo>=hi) return;
        int divider = partition(nums, lo, hi);
        quickSort(nums, lo, divider-1);
        quickSort(nums, divider+1, hi);
    }
    int partition(vector<int>&nums, int lo, int hi){
        int pivot_idx = (lo+hi)/2;  // 随机化pivot位置
        swap(nums[pivot_idx], nums[hi]);
        int& pivot = nums[hi];
        lo -= 1;
        while(lo<hi){
            while(++lo<hi&&nums[lo]<pivot){}
            while(lo<hi&&pivot<=nums[hi]){
                hi--;
            }
            swap(nums[lo], nums[hi]);
        }
        swap(nums[lo], pivot);
        return lo;
    }
};

归并
优点有稳定,可以外排等。
空间未优化, S ( n ) = O ( n log ⁡ ( n ) ) S(n)=O(n\log (n)) S(n)=O(nlog(n))

class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {
        mergeSort(nums, 0, nums.size());
        return nums;
    }
    void mergeSort(vector<int>& nums, int lo, int hi){
        if (hi-lo==1) return;
        int mid = (lo+hi)/2;
        mergeSort(nums, lo, mid);
        mergeSort(nums, mid, hi);
        int n = hi-lo, offset=lo, sub_n1 = mid-lo;
        vector<int> nums_cp(nums.begin()+lo, nums.begin()+hi);
        int i = 0;
        mid -= lo; lo = 0;
        while(true){
            if (lo>=sub_n1 || mid>=n){
                break;
            }
            if (nums_cp[lo]<=nums_cp[mid]){
                nums[offset+i++] = nums_cp[lo++];
            }else{
                nums[offset+i++] = nums_cp[mid++];
            }
        }
        while(lo<sub_n1){
            nums[offset+i++] = nums_cp[lo++];
        }
        while(mid<n){
            nums[offset+i++] = nums_cp[mid++];
        }
    }
};

空间优化, S ( n ) = O ( n ) S(n)=O(n) S(n)=O(n)

class Solution {
public:
    vector<int> nums_cp;
    vector<int> sortArray(vector<int>& nums) {
        nums_cp = vector<int>(nums);
        mergeSort(nums, 0, nums.size());
        return nums;
    }
    void mergeSort(vector<int>& nums, int lo, int hi){
        if (hi-lo==1) return;
        int mid = (lo+hi)/2;
        mergeSort(nums, lo, mid);
        mergeSort(nums, mid, hi);
        int n = hi-lo, offset=lo, sub_n1 = mid-lo;
        copy(nums.begin()+lo, nums.begin()+hi, nums_cp.begin());
        // vector<int> nums_cp(nums.begin()+lo, nums.begin()+hi);
        int i = 0;
        mid -= lo; lo = 0;
        while(true){
            if (lo>=sub_n1 || mid>=n){
                break;
            }
            if (nums_cp[lo]<=nums_cp[mid]){
                nums[offset+i++] = nums_cp[lo++];
            }else{
                nums[offset+i++] = nums_cp[mid++];
            }
        }
        while(lo<sub_n1){
            nums[offset+i++] = nums_cp[lo++];
        }
        while(mid<n){
            nums[offset+i++] = nums_cp[mid++];
        }
    }
};

数组的非递归归并排序
参考这位博主
子串长度每次翻倍,注意边界。

基数


希尔


计数



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值