面试&考研基本数据结构和算法——排序

排序

稳定性:具有相同关键字的记录排序后次序不变。

代码中数组都从0开始

冒泡排序

稳定,序列有序时O(n)

vector<int> BubbleSort(vector<int> v){
    bool f=true;
    while(f){
        f=false;
        for(int i=0;i<n-1;i++){
            if(v[i]>v[i+1]){
                f=true;
                swap(v[i],v[i+1]);
            }
        }
    }
    return v;
}

插入排序

序列分为两段,每次从后面拿一个元素插入前半段的正确位置。

稳定,数列几乎有序时效率很高。

vector<int> InsertionSort(vector<int> v){
    for(int i=1;i<n;i++){
        int j=i-1,cur=v[i];
        while(j>=0&&cur<v[j]){
            v[j+1]=v[j];
            j--;
        }
        v[j+1]=cur;
    }
    return v;
}

基数排序

按关键字重要性从低到高依次排序

稳定的排序算法,如果共有k个关键字且支持计数排序,那么复杂度为O(kn+关键字值域大小的和)

#define get(x,k) (x%p[i+1]/p[i])
vector<int> RadixSort(vector<int> v, int k=2){
    int p[10]={1},cnt[10];
    for(int i=1;i<k+1;i++)
        p[i]=p[i-1]*10;
    vector<int> res(n);
    for(int i=0;i<k;i++){
        memset(cnt,0,10*sizeof(int));
        for(int j=0;j<n;j++){
            cnt[get(v[j],i)]++;
        }
        for(int j=1;j<10;j++)
            cnt[j]+=cnt[j-1];
        for(int j=n-1;j>=0;j--){
            res[--cnt[get(v[j],i)]]=v[j];
        }
        v=res;
    }
    return res;
}

快速排序

每次挑选一个元素作pivot,将比它小的放在左侧,比它大的放在右侧;然后对被这个元素分割开的序列递归进行这个操作

partition有多种实现方法。都是不稳定的。

可以用快排的思想线性找第k大,每次挑选出pivot进行partition操作后,可以缩小第k大元素所在区间。

//in-place(原地)方案
int partition1(vector<int>& v,int l,int r){
    int pivot=v[l];
    while(l<r){
        while(l<r&&v[r]>=pivot)
            r--;
        v[l]=v[r];
        while(l<r&&v[l]<=pivot)
            l++;
        v[r]=v[l];
    }
    v[l]=pivot;
    return l;
}
int partition2(vector<int>& v,int l,int r){
    int pivot=v[r],cur=l;
    for(int i=l;i<r;i++){
        if(v[i]<=pivot){
            swap(v[i],v[cur]);
            cur++;
        }
    }
    swap(v[r],v[cur]);
    return cur;
}
void QuickSort(vector<int>& v,int low,int high){
   if(low>=high)
        return;
   int pivot=partition2(v,low,high);
   QuickSort(v,low,pivot-1);
   QuickSort(v,pivot+1,high);
}

归并排序

和快排不同的是,先递归,再对已排序的两段序列进行merge操作

归并排序还可以求逆序对,每次merge操作时如果后半段有需要提到前面的,那它之前比它大的就加在结果里。

void MergeSort(vector<int>& v,int l,int r){
    if(l>=r)
        return;
    int mid=(l+r)>>1;
    MergeSort(v,l,mid);
    MergeSort(v,mid+1,r);
    vector<int> tmp(r-l+1);
    int p=l,q=mid+1;
    for(int i=0;i<=r-l;i++){
        if(q>r||(p<=mid&&v[p]<v[q])){
            tmp[i]=v[p++];
        }else{
            tmp[i]=v[q++];
        }
    }
    for(int i=0;i<=r-l;i++){
        v[i+l]=tmp[i];
    }
}

堆排序

先在数组上建立最大堆,然后不断把top元素和堆最后的元素swap,并维护size-1的堆

不稳定

max_heapify(最大堆化):把top元素不断地和比它大的子节点交换,当堆仅发生了pop操作而改变时,执行一次max_heapify即可将堆恢复性质。即堆操作中的向下调整

void max_heapify(vector<int>& v,int st,int ed){
    int fa=st,son=fa*2+1;
    while(son<=ed){
        if(son+1<=ed&&v[son+1]>v[son])
            son++;
        if(v[fa]>=v[son])
            return;
        else{
            swap(v[son],v[fa]);
            fa=son;
            son=son*2+1;
        }
    }
}
void HeapSort(vector<int>& v,int len=n){
    for(int i=len/2-1;i>=0;i--){
        //len/2-1是len-1位置节点的父亲
        max_heapify(v,i,len-1);
    }
    for(int i=len-1;i>0;i--){
        swap(v[0],v[i]);
        max_heapify(v,0,i-1);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Absoler

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值