洛谷 P1177 【模板】快速排序【13种排序模版】
2017-08-03 09:19
489 查看
P1177 【模板】快速排序
题目描述
利用快速排序算法将读入的N个数从小到大排序后输出。快速排序是信息学竞赛的必备算法之一。对于快速排序不是很了解的同学可以自行上网查询相关资料,掌握后独立完成。(C++选手请不要试图使用STL,虽然你可以使用sort一遍过,但是你并没有掌握快速排序算法的精髓。)
输入输出格式
输入格式:输入文件sort.in的第1行为一个正整数N,第2行包含N个空格隔开的正整数a[i],为你需要进行排序的数,数据保证了A[i]不超过1000000000。
输出格式:
输出文件sort.out将给定的N个数从小到大输出,数之间空格隔开,行末换行且无空格。
输入输出样例
输入样例#1:5 4 2 4 5 1
输出样例#1:
1 2 4 4 5
说明
对于20%的数据,有N≤1000;对于100%的数据,有N≤100000。
题目链接:https://www.luogu.org/problem/show?pid=1177
下面给出几种排序方法:
1.松式基排
所谓普通基排,就是以65536为底,用位运算,把一个数拆成两部分,要循环两遍
松式基排,就是以256为底,用位运算把一个数拆成四部分,要循环四遍
为什么松式基排在WC的时候会更快呢,因为这样的话cnt数组刚好能装进L1高速缓存
下面给出如下代码:
#include <cstring> #include <cstdio> #include <algorithm> using namespace std; const int MAXN = 100010; const int BIT = 16; const int U = 65536; int n, a[MAXN]; inline int getd( int x, int d ) { return (x>>(d*BIT))&(U-1); } int cnt[U], b[MAXN]; void radix_sort() { int *x = a, *y = b; for( int d = 0; d < 2; ++d ) { for( int i = 0; i < U; ++i ) cnt[i] = 0; for( int i = 0; i < n; ++i ) ++cnt[getd(x[i],d)]; for( int i = 1; i < U; ++i ) cnt[i] += cnt[i-1]; for( int i = n-1; i >= 0; --i ) y[--cnt[getd(x[i],d)]] = x[i]; swap(x,y); } for( int i = 0; i < n; ++i ) printf( "%d ", x[i] ); } int main() { scanf( "%d", &n ); for( int i = 0; i < n; ++i ) scanf( "%d", a+i ); radix_sort(); return 0; }
2.归并排序
时间复杂度:O(nlogn)
注意:
1.其他排序算法的空间复杂度是O(1),而归并排序的空间复杂度很大,为O(n)。
2.下面的end是“末尾索引+1”,即数列末尾要留一个空位。
下面给出如下代码:
#include<iostream> using namespace std; int a[100010]; int temp[100010]; void merge_sort(int *a,int start,int end) { if(start+1>=end) //回渊 return; //int temp[start-end+5]; int mid=start+(end-start)/2; //划分阶段 int i=start,j=mid,count=start; merge_sort(a,start,mid); merge_sort(a,mid,end); while(i<mid||j<end) //合并解 { if(j>=end||(i<mid&&a[i]<=a[j])) { temp[count++]=a[i++]; } else temp[count++]=a[j++]; } //int x=0; for(int v=start;v<end;v++) { a[v]=temp[v]; } } int main() { int n; cin>>n; for(int i=0;i<n;i++) { cin>>a[i]; } merge_sort(a,0,n); for(int i=0;i<n;i++) { cout<<a[i]<<' '; } return 0; }
3.快速排序(优化读入读出)
下面给出如下代码:
#include <cstdio> #include <iostream> using namespace std; int a[100000]; int read_int() //读入优化 { int x,f=1; //f表示符号,x表示数值 char ch; while (ch=getchar(),ch<48||ch>57) //如果ch不是数字 if (ch=='-') f=-f; //如果是符号就改变符号 x=ch-48; //首位数字 while (ch=getchar(),ch>=48&&ch<=57) //接下来的每位数字 x=x*10+ch-48; //将数字添加进x内 return x*f; //返回数值 } void write_int(int x) { if (x==0) //判断0的情况 { putchar('0'); return; } int num=0; char c[11]; //然而我刚开始打的是10,然后发现输出10位数乱码了 while (x) //x!=0 c[++num]=x%10+48,x/=10; //保存每一位 while (num) //如果未输出完 putchar(c[num--]); //输出 } int sort(int l,int r) //快排,不用多说了吧 { int i,j,x; x=a[(l+r)>>1]; //基准 i=l; j=r; do { while (a[i]<x) ++i; while (a[j]>x) --j; //跳过排序完毕的元素 if (i<=j) { a[0]=a[i]; a[i]=a[j]; a[j]=a[0]; ++i; --j; //交换 } } while (i<=j); if (l<j) sort(l,j); if (i<r) sort(i,r); //排序左右子序列 } int main() { int n,i; n=read_int(); for (i=1;i<=n;i++) a[i]=read_int(); //快读的正确打开方式 sort(1,n); for (i=1;i<n;i++) { write_int(a[i]); putchar(' '); //输出的正确打开方式 } write_int(a ); putchar('\n'); //强迫症... return 233; }
4.利用stl实现堆排序,不是优先队列,比优先队列快上不少,而且容易记
下面给出如下代码:
#include <cstdio> #include <algorithm> #include <queue>//头文件 using namespace std; const int maxx = 100000 + 10; int Heap[maxx]; int main() { int n,num = 0,x; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&x),Heap[++num]=x,push_heap(Heap+1,Heap+num+1,greater<int>()); for(int i=1;i<=n;i++) printf("%d ",Heap[1]),pop_heap(Heap+1,Heap+num+1,greater<int>()),num--;//这几步是关键 return 0; }//代码比手搓堆短很多,而且时间差不多
5.朴素的堆排模板类
下面给出如下代码:
#include <bits/stdc++.h> using namespace std; template<typename T> //定义一个交换模板 void change(T& a,T& b) { T t; t=a;a=b;b=t; } template<typename T> //定义一个模板类 class Heap{ T data[100001]; //存储数据 void ify(int i); //维护堆 Heap(int); //构造函数 ~Heap(); //析构函数 void build(); //建堆 void heapsort(); //堆排序 istream& scan(istream&); //读入 ostream& print(ostream&); //输出 }; template<typename T> Heap<T>::Heap(int n_):n(n_) { } template<typename T> Heap<T>::~Heap() { } template<typename T> void Heap<T>::ify(int i) { int l=i<<1; int r=(i<<1)+1; int m; if (l<=size&&data[l]>data[i]) m=l; else m=i; if (r<=size&&data[r]>data[m]) m=r; if (m!=i) { change(data[m],data[i]); //找到最大数后交换并维护子树 ify(m); } } template<typename T> void Heap<T>::build() { int i; size=n; for (i=n/2;i>0;i--) //对每个非叶子节点维护一次 ify(i); } template<typename T> void Heap<T>::heapsort() { build(); for (int i=n;i>1;i--) { change(data[1],data[i]); //将最大数扔到最后 --size; ify(1); //维护 } } template<typename T> istream& Heap<T>::scan(istream& is) //读入 { for (int i=1;i<=n;i++) is>>data[i]; return is; } template<typename T> ostream& Heap<T>::print(ostream& os) //输出 { for (int i=1;i<n;i++) os<<data[i]<<' '; os<<data ; return os; } template<typename T> istream& operator>>(istream& is,Heap<T>& a) //重载运算符 { return a.scan(is); } template<typename T> ostream& operator<<(ostream& os,Heap<T>& a) //同上 { return a.print(os); } int main() { int n; cin>>n; Heap<int> a(n); cin>>a; a.heapsort(); cout<<a<<endl; }
6.优先队列priority_queue
下面给出如下代码:
#include<cstdio> #include<algorithm> #include<queue> using namespace std; int main(){ priority_queue<int,vector<int>,greater<int> > q; int n,x; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&x); q.push(x); } for(int i=1;i<=n;i++){ x=q.top(); printf("%d ",x); q.pop(); } return 0; }
7.用一个红黑树来实现
下面给出如下代码:
#include <cstdlib> #include <iostream> #include <set> #include <string> using namespace std; int main(int argc, char *argv[]) { multiset<int>sort;//新建一个红黑树 int n; scanf("%d",&n); for(int i=1;i<=n;i++) { int a; cin>>a; sort.insert(a);//将数据插入红黑树 } set<int>::iterator it; for(it=sort.begin();it!=sort.end();it++) cout << *it<<' ';//遍历输出红黑树,即排序结果 cout<< endl; return 0; }
8.排序二叉树
有一种很好的办法是用排序二叉树。。。建好树后中序遍历输出。。。就好了。
不过二叉排序树有退化成链的可能,所以可以用splay或是treap甚至AVL以及红黑树来排序。。。
伸展树(splay)的写法:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cstring> #define xh(a,b,c)for(int a=(b);a<=(c);a++) #define dxh(a,b,c)for(int a=(b);a>=(c);a--) #define hy(a)memset(a,0,sizeof(a)) using namespace std; void qin(int &x){//快速读入 int base=1,num; char c=getchar(); while(!(c=='-'||c>='0'&&c<='9'||c==EOF))c=getchar(); if(c==EOF)exit(0); if(c=='-')base=-1,c=getchar(); num=c-'0'; c=getchar(); while(c>='0'&&c<='9'){ num*=10; num+=c-'0'; c=getchar(); } x=num*base; } char integ[50]; void qout(int x){//快速输出 if(x<0)putchar('-'),x=-x; int len=0; do{ integ[len++]=x%10+'0'; x/=10; }while(x); while(len--){ putchar(integ[len]); } } struct jd{//静态splay int x; int l,r,h; }; const int N=101010; jd bst ; int root,n;//root表示根节点的编号 void lj(int u,int d,int fx){ if(fx==1)bst[u].r=d; else bst[u].l=d; bst[d].h=u; } void zig(int x){//左旋 int b1=bst[x].l,b2=bst[x].r,h=bst[x].h,b3=bst[h].r; root=x; bst[x].h=0; lj(x,h,1); lj(x,b1,-1); lj(h,b2,-1); lj(h,b3,1); } void zag(int x){//右旋 int b1=bst[x].l,b2=bst[x].r,h=bst[x].h,b3=bst[h].l; root=x; bst[x].h=0; lj(x,h,-1); lj(x,b2,1); lj(h,b3,-1); lj(h,b1,1); } void zigzig(int x){//略。。。反正是向上调 int b1=bst[x].l, b2=bst[x].r, h=bst[x].h, b3=bst[h].r, hh=bst[h].h, b4=bst[hh].r, hhh=bst[hh].h; if(hhh==0){ root=x; bst[x].h=0; }else if(bst[hhh].l==hh)lj(hhh,x,-1); else lj(hhh,x,1); lj(x,h,1); lj(h,hh,1); lj(x,b1,-1); lj(h,b2,-1); lj(hh,b3,-1); lj(hh,b4,1); } void zagzag(int x){//略。。。反正是向上调*2 int h=bst[x].h, hh=bst[h].h, hhh=bst[hh].h, b1=bst[hh].l, b2=bst[h].l, b3=bst[x].l, b4=bst[x].r; if(hhh==0){ root=x; bst[x].h=0; }else if(bst[hhh].l==hh)lj(hhh,x,-1); else lj(hhh,x,1); lj(x,h,-1); lj(h,hh,-1); lj(x,b4,1); lj(h,b3,1); lj(hh,b1,-1); lj(hh,b2,1); } void zigzag(int x){//略。。。反正是向上调*3 int b1=bst[x].l, b2=bst[x].r, h=bst[x].h, b3=bst[h].r, hh=bst[h].h, b4=bst[hh].l, hhh=bst[hh].h; if(hhh==0){ root=x; bst[x].h=0; }else if(bst[hhh].l==hh)lj(hhh,x,-1); else lj(hhh,x,1); lj(x,h,1); lj(x,hh,-1); lj(hh,b1,1); lj(h,b2,-1); lj(h,b3,1); lj(hh,b4,-1); } void zagzig(int x){////略。。。反正是向上调 int b1=bst[x].l, b2=bst[x].r, h=bst[x].h, b3=bst[h].l, hh=bst[h].h, b4=bst[hh].r, hhh=bst[hh].h; if(hhh==0){ root=x; bst[x].h=0; }else if(bst[hhh].l==hh)lj(hhh,x,-1); else lj(hhh,x,1); lj(x,h,-1); lj(x,hh,1); lj(h,b1,1); lj(hh,b2,-1); lj(h,b3,-1); lj(hh,b4,1); } void splay(int x){//伸展操作(把x节点调到根节点) while(bst[x].h){ if(bst[bst[x].h].h==0){ if(bst[bst[x].h].l==x)zig(x); else zag(x); } else{ int h=bst[x].h,hh=bst[h].h; if(bst[h].l==x){ if(bst[hh].l==h)zigzig(x); else zigzag(x); } else{ if(bst[hh].l==h)zagzig(x); else zagzag(x); } } } } void ins(int r,int i){//插入 if(bst[i].x<bst[r].x){ if(bst[r].l==0){ lj(r,i,-1); splay(i);//每当插入一个数后都要把这个数调到根节点 } else ins(bst[r].l,i); } else{ if(bst[r].r==0){ lj(r,i,1); splay(i);;//每当插入一个数后都要把这个数调到根节点 } else ins(bst[r].r,i); } } void bl(int x){//中序遍历 if(x==0)return; bl(bst[x].l); qout(bst[x].x); putchar(' '); bl(bst[x].r); } int main(){ qin(n); qin(bst[1].x); root=1; xh(i,2,n){ qin(bst[i].x); ins(root,i); } bl(root); putchar('\n'); return 0; }
9.可并堆
#include<bits/stdc++.h> using namespace std; #define fr(i,a,b) for(int i=(a),_end_=(b);i<=_end_;i++) struct tree{ tree *l,*r,*f; int v,sl,sr; tree(){ l=r=f=NULL; v=sl=sr=0; } }*root,*k,*d; tree* merge(tree *x,tree *y){//合并 if(x==NULL)return y; if(y==NULL)return x; if(x->v>y->v) swap(x,y); x->r=merge(x->r,y); x->sr++; if((x->sl)<(x->sr)){ swap(x->l,x->r); swap(x->sl,x->sr); } return x; } void insert(int x){//插入 k=new tree; k->v=x; if(root==NULL)root=k; else root=merge(root,k); } int top(){//顶端元素 if(root!=NULL)return root->v; return -1; } void pop(){//弹出 if(root!=NULL)root=merge(root->l,root->r);//合并左右子数 } int main(){ root=NULL; int n; scanf("%d",&n); fr(i,1,n){ int a; scanf("%d",&a); insert(a); } fr(i,1,n){ printf("%d ",top()); pop(); } return 0; }
10.希尔排序
#include <cstdio> using namespace std; int i,j,k,n,m,x,y,t,d,a[100001]; void ShellInsert(int* pDataArray, int d, int iDataNum){ for (int i = d; i < iDataNum; i += 1){ int j = i - d; int temp = pDataArray[i]; while (j >= 0 && pDataArray[j] > temp){pDataArray[j+d] = pDataArray[j];j -= d;} if (j != i - d)pDataArray[j+d] = temp; } } void ShellSort(int* pDataArray, int iDataNum){ int d = iDataNum / 2; while(d >= 1){ShellInsert(pDataArray, d, iDataNum);d = d / 2;} } int main(){ scanf("%d",&n);if (n==0) return 0; for (i=0;i<n;i++) scanf("%d",&a[i]); ShellSort(a,n); for (i=0;i<n;i++) printf("%d ",a[i]); return 0; }
11.用动态插入堆排序
#include <iostream> #include <cstdio> #include <cstring> using namespace std; typedef long long ll; ll heap[1001000]; #define lson(x) x<<1 #define rson(x) x<<1|1 #define fa(x) x>>1 ll N; struct Heap{ int size; Heap(){ size=0; } void pushDown(int i){ //从顶部向下推至合适位置 int l,r,k; while(lson(i)<=size){ l=lson(i);r=rson(i);k=i; if(heap[k]>heap[l]){ k=l; } if(r<=size && heap[k]>heap[r]){ k=r; } if(k!=i){ swap(heap[i],heap[k]); i=k; }else break; } } void pushUp(int i){ // 从底部推至合适位置 while(fa(i)>=1){ if(heap[fa(i)]>heap[i]){ swap(heap[fa(i)],heap[i]); i=fa(i); }else break; } } void pop(){ //删除堆顶元素 heap[1]=heap[size--]; pushDown(1); } ll top(){ return heap[1]; } void insert(int x){ //插入一个新元素到堆底 heap[++size]=x; pushUp(size); } }H; inline ll read(){ ll a=0; char ch=getchar(); bool flag = false; while(ch>'9' || ch<'0' || ch=='-'){ if(ch=='-') flag=true; ch=getchar(); } while(ch>='0' && ch<='9'){ a=a*10+ch-'0'; ch=getchar(); } if(flag) a=-a; return a; } int main(){ N=read();ll v; for(int i=1;i<=N;++i){ v=read();H.insert(v); } while(H.size){ printf("%lld ",H.top()); H.pop(); } return 0; }
12.基数排序(O(n))
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #define Z 1000000+10 #define K 10+10//位数设为20 , 11 也可以 #define FORZ(a,b,c) for(a=b;a<=c;a++) #define FORJ(a,b,c) for(a=b;a>=c;a--) #define M0(a) memset(a,0,sizeof(a)) using namespace std; int a[Z]; int b[Z]; int cnt[K]; int getmax(const int n) { int i,p=1,sum=10; FORZ(i,1,n) { while(a[i]>=sum) { sum*=10; p++; } } return p; } void JS_sort(const int n) { int i,j,k,l,o,p,u; int wei=getmax(n); int ord=1; FORZ(k,1,wei) { M0(cnt); FORZ(i,1,n) { u=a[i]/ord%10; cnt[u]++; } FORZ(i,1,9) { cnt[i]+=cnt[i-1]; } //滚包裹 FORJ(i,n,1) { u=a[i]/ord%10; b[cnt[u]]=a[i]; cnt[u]--; } FORZ(i,1,n) { a[i]=b[i]; } ord*=10; } } int main() { int n,i,j,k,l,u,o,p; scanf("%d",&n); FORZ(i,1,n)scanf("%d",&a[i]); JS_sort(n); FORZ(i,1,n)printf("%d ",a[i]); }
13.最不值得一提的sort(不建议,毕竟这是一道模版题)
#include <bits/stdc++.h> using namespace std; typedef long long ll; ll a[100010]; int main() { int n; cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; sort(a+1,a+1+n); for(int i=1;i<n;i++) cout<<a[i]<<" "; cout<<a <<endl; return 0; }
相关文章推荐
- 洛谷 P1177 【模板】快速排序
- 洛谷 P1177 【模板】快速排序
- 【排序】洛谷 P1177 【模板】快速排序
- P1177 【模板】快速排序
- 快速排序模板和二分查找
- 洛谷 P1177 快排【模板】
- 利用c++模板实现快速排序
- 洛谷 P3390 【模板】矩阵快速幂
- 快速排序的模板代码
- 快速排序模板
- 快速排序----模板实现
- 快速排序模板,一分钟内写出
- .洛谷P【快速排序】【模板级】
- 部分题目 ---DP 快速幂模版 dijstra 排序辅助
- C++模板快速排序和Stooge排序
- 快速排序模板
- [模板]快速排序
- 洛谷 P1939 【模板】矩阵加速(数列):优化递推式的方法——矩阵快速幂
- 用模板写快速排序-链表
- 快速排序模板、