Acwing排序算法模板

快速排序算法(快排)O(N*logN) + O(1)

非稳定(即,排序后的相对顺序和排序之前有可能不同)

 快排中的边界处理

选取每次快排过程中的 目标数值 的时候,要选取 中位数向上取整 target = data[ (L+R+1)/2 ],避免仅包含两个数组的无限循环。

#include <iostream>
#include <vector>

using namespace std;

template<typename T>
void quickSort(vector<T> & data, int l, int r){
    // 需要重写 = 和 < 、 >  运算符 有可能需要重写swap()函数
    if( l >= r ) return;
    T x = data[(l+r+1)/2];
    int left = l - 1, right = r + 1;
    while(left < right){
        do ++left; while(data[left] < x) ;
        do --right; while(data[right] > x) ;
        if( left < right ) swap(data[left], data[right]);
    }
    quickSort(data, l, left-1);
    quickSort(data, left, r);
}

快速选择算法 O(N) + O(1)

用于求数组排序后的 第k个数

与快排类似,但是每次只选择一半,即k所在的那一半进行迭代

#include <iostream>
#include <vector>
using namespace std;

template<typename T>
T quickSelect(vector<T> & data,int l,int r,int k){
    //重写 T 的 比较符 >、< 
    if(l == r) return data[l];

    T x = data[ (l + r) / 2 ];
    int left = l - 1, right = r + 1;
    while(left < right){
        while(data[++ left] < x) continue;
        while(data[-- right] > x) continue;
        if(left < right) swap(data[left], data[right]);
    }
    int lLen = right - l +1;
    if(lLen >= k){
        return quickSelect(data, l, right, k);
    }
    return quickSelect(data, right+1, r, k-lLen);
}

归并排序算法 O(N*logN) + O(N)

稳定(即,排序后的相对顺序和排序之前相同)

#include <iostream>
#include <vector>

using namespace std;

template <class T>
void mergeSort(vector<T> & data, int L, int R){
    if(L >= R) return;
    int mid = L + ((R - L) >> 1);
    mergeSort(data, L, mid);
    mergeSort(data, mid+1, R);
    int idx1 = L, idx2 = mid + 1;
    vector<T> tpdata(R - L + 1);
    int tpidx = 0;
    while(idx1 <= mid && idx2 <= R)
        if(data[idx1] <= data[idx2]) tpdata[tpidx ++] = data[idx1 ++];
        else tpdata[tpidx ++] = data[idx2 ++];
    while(idx1 <= mid) tpdata[tpidx ++] = data[idx1 ++];
    while(idx2 <= R) tpdata[tpidx ++] = data[idx2 ++];
    for(int i = L; i <= R; i ++) data[i] = tpdata[i - L];
}

逆序对数量  O(N*logN) + O(N)

返回一个数组中的逆序对数量。基于归并排序。

#include <iostream>
#include <vector>
using namespace std;
template<class T>
long long reversePair(vector<T> & data, int L, int R){
    if(L >= R) return 0;
    int mid = L + R >> 1;
    long long res = reversePair(data, L, mid) + reversePair(data, mid + 1, R);
    vector<T> tpdata(R - L + 1, 0);
    int tpL = L, tpR = mid + 1, idx = 0;
    while(tpL <= mid && tpR <= R){
        if(data[tpL] <= data[tpR]) tpdata[idx ++] = data[tpL ++];
        else{
            tpdata[idx ++] = data[tpR ++];
            res += mid - tpL + 1;
        }
    }
    while(tpL <= mid) tpdata[idx ++] = data[tpL ++];
    while(tpR <= R) tpdata[idx ++] = data[tpR ++];
    for(int i = L, idx = 0; i <= R; i ++){
        data[i] = tpdata[idx ++];
    }
    return res;
}

二分查找法  O(logN) O(1)

vector<T>必须有序,单调递增

containS :若数组包含target,则返回索引,否则返回-1

leftBound: 若数组包含target,则返回target的最左位置,否则返回-1

rightBound:若数组包含target,则返回target的最右位置,否则返回-1

还有另外一种规则引出的函数为,返回>=target的最左位置 / 返回<=target的最右位置,则只需要把函数最后的if(data[l] == target)删掉即可。

二分法中的边界处理

二分找最右边界的时候,要选取中位数向上取整 mid = ( L + R + 1) / 2,避免仅含两个数的数组无限循环。

#include <iostream>
#include <vector>

using namespace std;

template<class T>
int containS(vector<T> &data,T target){
    //重写T的 ==  <   >
    int l = 0, r = data.size() - 1;
    while(l < r){
        int mid = l+ ((r - l) >> 1);
        if(data[mid]>target) r = mid - 1;
        else if(data[mid] == target) return mid;
        else l = mid + 1;
    }
    if(data[l] == target) return l;
    return -1;
}

template<class T>
int leftBound(vector<T> &data,T target){
    //重写T的 ==  <   >
    int l = 0, r = data.size() - 1;
    while(l < r){
        int mid = l+ ((r - l) >> 1);
        if(data[mid]>=target) r = mid;
        else l = mid + 1;
    }
    if(data[l] == target) return l;
    return -1;
}

template<class T>
int rightBound(vector<T> &data,T target){
    //重写T的 ==  <   >
    int l = 0, r = data.size() - 1;
    while(l < r){
        int mid = l+ ((r - l + 1) >> 1);
        if(data[mid] <= target) l = mid;
        else r = mid - 1;
    }
    if(data[l] == target) return l;
    return -1;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值