排序入门

Posted heower

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了排序入门相关的知识,希望对你有一定的参考价值。

排序:外部排序,内部排序

以下内容 无须铭记
内部排序是在内存中进行排序
外部排序 当文件较大,内存无法全部储存,将文件存放在外面,使用......方法让文件依次进入内存排序
我们接触到的排序都是内部排序

bogo排序:随机打乱,检查是否有序。

srand(time(NULL))

for(;;){  //while(1)
    bool pd=1;
    for(i:1->n-1) if(a[i]>a[i+1]){
        pd=0;
        break;
    }
    if(pd) break;
    for(i:1->n) {  
        int j=rand()%n+1;
        swap(a[i],a[j]);
    }
    // random_shuffle(a+1,a+n+1);
}

------------------------------------华------丽------的------分------割------线-------------------------------------

八大排序:

插入排序: 直接插入排序,希尔排序
选择排序:简单选择排序,堆排序

交换排序:冒泡排序,快速排序

归并排序

基数排序

——————————————————————————————————————————————————————————
简单介绍以下各种排序:
直接插入排序:从未排序的数中依次枚举,插入到已排序的序列中

for(int i=2;i<=n;++i){
    int j=i-1;
    int tmp=a[i];
    while(j&&a[j]>tmp) a[j+1]=a[j],j--;
    if(j!=i-1) a[j+1]=tmp;
}
//时间复杂度:O(n^2)
//空间复杂度:O(n)
//稳定排序

希尔排序:插入排序改进版,选择一个增量d,将d的倍数放在一组,进行插入排序,如图:
技术分享图片

for(int d=n/2;d;d>>=1) {
    for(i=d;i<=n;++i) {
        int j=i-d;
        int tmp=a[i];
        while(j&&a[j]>tmp) a[j+d]=a[j],j-=d;
        if(j+d!=i) a[j+d]=tmp;
    }
}
//时间复杂度:O(玄学)(最优O(n^1.3))
//空间复杂度:O(n)
//不稳定排序

简单选择排序:在未排序数列中,找出最小的数与第一个交换,再在未排序数列中,找出最小的数与第二个交换

简单选择排序:

for(int i=1;i<=n;++i){
    int k=i;
    for(j=i+1;j<=n;++j) if(a[j]<a[k]) k=j;
    swap(a[k],a[i]);
}
//时间复杂度:O(n^2)
//空间复杂度:O(n)
//不稳定排序

冒泡排序:不断交换相邻两个值

for(int i=1;i<n;++i){
    bool change=0;
    for(j=1;j<n-i;++j) if(a[j]>a[j+1]) swap(a[j],a[j+1]);
    if(!change) break;
}
//时间复杂度:O(n^2)
//空间复杂度:O(n)
//稳定排序

附:
鸡尾酒排序:双向冒泡排序排序,见图
技术分享图片

int l=1,r=n;
while(l<r){
    for(i=l;i<r;++i) if(a[i]>a[i+1]) swap(a[i],a[i+1]);
    r--;
    for(i=r;i>l;--i) if(a[i-1]>a[i]) swap(a[i-1],a[i]);
    l++;
}
//时间复杂度:O(n^2)
//空间复杂度:O(n)
//稳定排序

桶排:不常用但很好用,将所有的数放入到桶中,依次取出

int Max=0,Min=oo;
for(int i=1;i<=n;++i) t[a[i]]++,Max=max(Max,a[i]),Min=min(Min,a[i]);
for(int i=Min;i<=Max;++i) while(t[i]) a[++cnt]=i,t[i]--;
//时间复杂度:O(max_num)
//空间复杂度:O(n+max_num)
//不稳定排序

——————————————————————————————————————————————————————————
当然,除了堆排序、快速排序、归并排序、基数排序,其余的基本不用

堆排序 维护堆,将 数据放入一个堆中 依次取出
实现 : 大根堆 priority_queue<数据类型>
如 : priority_queue\(<int>\)
小根堆 priority_queue<数据类型,容器,比较函数>
如 : priority_queue\(,greater\)$ >
(注:greater<> 是c++标准模板库(STL) 自带比较函数)

priority_queue<int> q;//priority_queue<int,vector<int>,greater<> > q;
for(int i=1;i<=n;++i) q.push(a[i]);
while(!q.empty()) a[++cnt]=q.top(),q.pop();
//时间复杂度:O(nlogn)
//空间复杂度:O(n)
//不稳定排序

———————————————————————————————————————————————————————————

归并排序 不断递归二分,使子区间有序,在合并成一个大区间
如图:
技术分享图片

void Merge_sort(int l,int r){
    if(l==r) return ;
    int mid=l+r>>1;
    Merge_sort(l,mid);
    Merge_sort(mid+1,r);
    int i=l,j=mid+1,cnt=0;
    while(i<=mid&&j<=r)
        if(a[i]<=a[j])  b[++cnt]=a[i++];
        else b[++cnt]=a[j++];
    while(i<=mid) b[++cnt]=a[i++];
    while(j<=r) b[++cnt]=a[j++];
    for(i=1;i<=cnt;++i) a[l+i-1]=b[i];
}
//时间复杂度:O(nlogn)
//空间复杂度:O(2n)
//稳定排序

———————————————————————————————————————————————————————————

快速排序 以 小-->大 排序 二分,选择一个基准,在基准左边选一个小于基准的元素
在右边选一个大于基准的元素
交换
再递归,分别对左右区间操作,将大于基准的放在基准右边
小于基准的放在基准左边

实现 : 小-->大 sort(a+1,a+n+1); (区间是 左闭右开)
大-->小 sort(a+1,a+n+1,greater\(<int>\)())
防止相同元素改变顺序:stable_sort();

void Quick_sort(int l,int r){
    int mid=a[l+r>>1];
    int i=l,j=r;
    while(i<=j) {
        while(a[i]<mid) i++;
        while(a[j]>mid) j--;
        if(i<=j) swap(a[i],a[j]),i++,j--;
    }
    if(i<r) Quick_sort(i,r);
    if(j>l) Quick_sort(l,j);
}
//时间复杂度:O(nlogn)
//空间复杂度:O(n)
//不稳定排序

————————————————————————————————————————————————————————————

基数排序 按位 (从低位到高位) 排序,
以 小-->大 排序 从低位--高位 按每一位 由小到大进行排序,具体实现可用通排

如图:
技术分享图片
技术分享图片

void BCN_sort(int n,int Max_len){
    int t[10][Max]={0};
    int k=1,m=1,cnt=1;
    while(k<Max_len){
        for(i=1;i<=len;++i){
            if(a[i]<m) t[0][cnt]=a[i];
            else {
                int pos=a[i]/m%10;
                t[pos][cnt]=a[i];
            }
            cnt++;
        }
        Collect(a,t);
        cnt=0;
        m*=10;
        k++;
    }
}
//时间复杂度:O(Max_len*n)
//空间复杂度:O(10*n)
//稳定排序

————————————————————————————————————————————————————————————

用堆来排序并不多见,因为堆是可以支持O(1)查询 O(log n)插入、删除
所以 在一些取最值的题目中,才能体现他的优势

快排是OI中用的最多的排序,标准模板库中的 sort 与自己写的快速排序要快得多,尽管它是STL
况且,你可你自己写比较函数来改变 sort 的比较键值(Key)
虽然它不稳定,但应该不会有人要出数据去卡快速排序
至于快排的另一用法 查询某一元素在序列中是第几大,也可以用 nth_element() 来实现

基数排序,也不常用,讲它的是因为 后缀数组(SA) 中会用到它

归并排序 本来不想讲,它虽然稳定,真不常用,但他的思想非常重要,在CDQ分治中它起着很大作用

————————————————————————————————————————————————————————————

排序应用:去重、离散化

去重:排序后 保留当前元素和前一个元素不同的

void Unique(){
    sort(a+1,a+n+1);
    int cnt=0;
    for(int i=1;i<=n;++i) if(a[i]!=a[i-1]) b[cnt++]=a[i];
}

离散化:一个大区间有许多浪费的位置,而且我们只需要它们的大小关系,可以将它们按大小重新编号

struct array{
    int Ori_num,Now_num,id;
    friend bool operator < (array x,array y){
        return x.Ori_num<y.Ori_num;
    }
}a[N];

boold comp(array x,array y){
    return x.id<y.id;
}

void Discre{
    sort(a+1,a+n+1);
    int cnt=0;
    for(int i=1;i<=n;++i) if(a[i].Ori_num!=a[i-1].Ori_num) a[i].Now_num=++cnt;
    sort(a+1,a+n+1,comp);
}

————————————————————————————————————————————————————————————
简单题:
拯救世界-紧急召集

以上是关于排序入门的主要内容,如果未能解决你的问题,请参考以下文章

初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段

Atom编辑器入门到精通 Atom使用进阶

Cg入门20:Fragment shader - 片段级模型动态变色(实现汽车动态换漆)

Cg入门19:Fragment shader - 片段级模型动态变色

Cg入门16:Fragment shader - 片段级光照

Atom编辑器入门到精通 Atom使用进阶