由入门到入土的排序专题

排序

选择排序

//选择排序的核心思想是找到一个最小的元素(第二层循环中ji就是最小元素在无序数组中的编号)然后把它放到最前面
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
int a[99999999],n;
void swap(int &l,int &k){
    int t=l;
    l=k;
    k=t;
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=1;i<=n;i++){
        int ji=i;
        for(int j=i+1;j<=n;j++){
            if(a[j]<a[ji])ji=j;
        }
        if(ji!=i)
//      {//或者这样也行 
//          int t=a[i];
//          a[i]=a[ji];
//          a[ji]=t;
//      }
            swap(a[i],a[ji]);//要传址调用 
    }
    cout<<endl;
    for(int i=1;i<=n;i++)
        printf("%d ",a[i]);
    return 0;
}

正版冒泡

//冒泡排序的核心思想是一遍一遍地比较相邻两个数并交换顺序
#include<iostream>
#include<cstdio>
using namespace std;
int a[99999999],n;
int main(){
    cin>>n;
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=n-1;i>=1;i--){
        for(int j=0;j<=i;j++){
            if(a[j]>a[j+1]) swap(a[j],a[j+1]);
        }
    }
    for(int i=1;i<=n;i++)printf("%d ",a[i]);
    return 0;
}

盗版冒泡

#include<iostream>
#include<cstdio>
using namespace std;
int a[99999999],n;
int main(){
    cin>>n;
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=1;i<=n;i++){
        for(int j=i+1;j<=n;j++){
            if(a[i]>a[j]) swap(a[i],a[j]);
        }
    }
    for(int i=1;i<=n;i++)printf("%d ",a[i]);
    return 0;
}

插排

//顾名思义
#include<iostream>
#include<cstdio>
using namespace std;
int a[99999999],n,i,j;
void yi(int p,int q)
{
    for(int h=q;h>p;h--)a[h]=a[h-1];
}
int main(){
    cin>>n;
    for( i=1;i<=n;i++)scanf("%d",&a[i]);
    for( i=2;i<=n;i++){//a[i]为需要插入的数 
        for( j=i-1;j>=1;j--)//寻找插入点 
            if(a[j]<a[i])break;
            if(j!=i-1){//需要将a[i]插入a[j]后 
                int temp=a[i];
                yi(j+1,i);
                a[j+1]=temp;
            }
    }
    cout<<endl;
    for(i=1;i<=n;i++)printf("%d ",a[i]);
    return 0;
}

桶排

//开一个数组记录所有数字出现了几次,最后按数组顺序输出
#include<iostream>
#include<cstdio>
using namespace std;
int a[99999999],n,ji;
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        scanf("%d",&ji);
        a[ji]++;
    }
    for(int i=0;i<=n;i++){
        while(a[i]){
            printf("%d ",i);
            a[i]--;
        }
    }
    return 0;
}

快速排序

#include<bits/stdc++.h>
using namespace std;
int n,a[100005];
int read(){//快读优化
	int x=0;char ch=getchar();
	while(ch>'9'||ch<'0')ch=getchar();
	while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return x;
}
void quick_sort(int l,int r){
	if(l>=r)return ;
	int mid=a[(l+r)>>1],i=l,j=r;//我习惯用将基准数设为中间的那个数
	while(i<=j){
		while(a[i]<mid)++i;//不能加‘=’,否则当mid为整个数组中的最大数时会陷入死循环
		while(a[j]>mid)--j; 
		if(i<=j){//要特判,否则i>j了就是在帮倒忙了
			swap(a[i],a[j]);
			++i,--j;//不在原地踏步
		}
	}
	if(l<j)quick_sort(l,j);//!!! 一遍快排之后i>j了所以~
	if(r>i)quick_sort(i,r);
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		a[i]=read();
	}
	quick_sort(1,n);
	for(int i=1;i<=n;i++){
		cout<<a[i]<<" ";
	}
}

三数取中+冒泡版 快排

//
#include<iostream>
#include<cstdio>
using namespace std;
int a[99999999],n;
void cha(int p,int q){//p<q 
	int ji=0,j;
    for(int i=p+1;i<=q;i++){
		for(j=p;j<i;j++)if(a[i]<a[j])break;
		ji=a[i];
		for(int k=i-1;k>=j;k--){//千万记得是倒序赋值
			a[k+1]=a[k];
		}
		a[j]=ji;
    }
}
void quick(int le,int ri){
    if(le>=ri)return;
    if(ri-le<=10)cha(le,ri);
    int t=(le+ri)/2,mid,x=le,y=ri;//在左端点右端点和中点位置的三个数中选取大小排中间的数,并将另外两数按大小分别赋给左右端点
    if(a[le]<a[t]){
        if(a[t]>a[ri]){
            int w=a[t];
            a[t]=a[ri];
            a[ri]=w;
        }
    }
    if(a[le]>a[t]){
        int w=a[t];
        a[t]=a[le];
        a[le]=w;//a[le]<a[t]
        if(a[t]>a[ri]){
            int w=a[t];
            a[t]=a[ri];
            a[ri]=w;
        }
    }
    mid=a[t];
    while(x<=y){
        while(a[x]<mid)x++;
        while(a[y]>mid)y--;
        if(x<=y){
            int w=a[x];
            a[x]=a[y];
            a[y]=w;
            x++;
            y--;
        }
    }
    if(le<y)quick(le,y);
    if(x<ri)quick(x,ri);
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	quick(1,n);
    for(int i=1;i<=n;i++)printf("%d ",a[i]);
	return 0;
}

归并排序

#include<iostream>
#include<cstdio>
using namespace std;
int a[99999999],b[99999999],n;
void gui(int le,int ri)
{
    if(le==ri)return;
    int mid=(le+ri)/2,x=le,y=mid+1,k=le;
    gui(le,mid);
    gui(mid+1,ri);
    while(x<=mid&&y<=ri)
        if(a[x]<a[y])b[k++]=a[x++];
        else b[k++]=a[y++];
    while(x<=mid)b[k++]=a[x++];
    while(y<=ri)b[k++]=a[y++];
    for(int g=le;g<=ri;g++)a[g]=b[g];
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    gui(1,n);
    for(int i=1;i<=n;i++)printf("%d ",a[i]);
    return 0;
}

基数排序

基数排序的核心思想是按顺序(从高往低或者从低往高)比较每个数字的个位十位百位等等,每次按当前数位上的数值大小将数组重新排列,然后将新数列按下一位上的数值大小比较并再次排序,以此类推即可得到答案
#include<iostream>
#define ll long long 
using namespace std;
ll ma,n,a[200000],tub[15][200000],bas[15]={1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000,10000000000,100000000000,1000000000000,10000000000000},k;
int main(){
	cin>>n;
	for(ll i=1;i<=n;i++){
		cin>>a[i];
		ll t=1;
		while(a[i]>=bas[t])++t;
		ma=max(ma,t);//统计有多少位 
	}
	for(ll t=1;t<=ma;t++){
		for(ll i=1;i<=n;i++){
			k=(a[i]%(bas[t]))/bas[t-1];tub[k][++tub[k][0]]=a[i];//按当前位大小放入桶子里 
		}
		ll now=1;
		for(ll i=1;i<=n;i++)
			for(k=0;k<=9;k++){
				for(ll ji=1;ji<=tub[k][0];ji++)
					a[now++]=tub[k][ji];//按桶子的顺序重新排序 
					tub[k][0]=0;//记录桶子里有多少个数 
			}
	}
	for(ll i=1;i<=n;i++)cout<<a[i]<<" ";
}

测试数据生成器

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<ctime>
using namespace std;
int main(){
    freopen("testdata.in","w",stdout);
    srand((unsigned)time(NULL));
    for(int i=1;i<=10000;i++)
        printf("%d ",rand());
    return 0;
}
posted @ 2021-09-25 12:54  lqhsr  阅读(60)  评论(0编辑  收藏  举报