c++八大排序
目录:
- 1.计数排序
- 2.基数排序
- 3.快速排序
- 4.冒泡排序
- 5.选择排序
- 6.归并排序
- 7.堆排序
- 8.插入排序
计数排序
计数排序是一种稳定的算法,能在线性时间O(n+k)对n个数进行排序,范围【0,k】
将A数组排序时,先将小于等于Ai的数记录在C中,根据C的数值计算Ai在B的位置。
时间复杂度:o(n+k)
空间复杂度:k+n
是否稳定:稳定
代码实现:
for(int i=0;i<n;i++){
scanf("%d",&A[i+1]);
C[A[i+1]]++;
}
for(int i=1;i<M;i++)C[i]+=C[i-1];
for(int j=1;j<=n;j++){
B[C[A[j]]]=A[j];
C[A[j]]--;
}
for(int i=1;i<=n;i++)printf("%d ",B[i]);
基数排序
基数排序(gay sort)非常快,史(小C)称最快排序。但是只能排自然数。
时间复杂度:O(d(n+k)) k为基数,d为最大的位数
空间复杂度:n+r
是否稳定:稳定
代码实现:
#define N 65536
#define M 100005
int P=(1<<16)-1;
void gaysort(){
memset(cnt,0,sizeof(cnt));
for(int i=0;i<=N;i++)cnt[A[i]&P]++;
for(int i=1;i<=N;i++)cnt[i]+=cnt[i-1];
for(int i=n;i>=1;i--)B[cnt[A[i]&P]--]=A[i];
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=n;i++)cnt[(b[i]>>16)&P]++;
for(int i=1;i<=N;i++)cnt[i]+=cnt[i-1];
for(int i=n;i>=1;i--)A[cnt[(B[i]>>16)&P]--]=B[i];
}
快速排序
快速排序(quick sort)是一种比较快的原地排序但是不稳定。
平均复杂度:O(nlog(n))
最差复杂度:O(n^2)
空间复杂度:O(n)
是否稳定:不稳定
代码实现:
void Sort(int L,int R){
if(L>R)return;
int key=A[L];
int a=L,b=R;
while(a<b){
while(a<b&&A[b]>=key)b--;
if(a<b)A[a]=A[b];
while(a<b&&A[a]<=key)a++;
if(a<b)A[b]=A[a];
}
A[a]=key;
if(a-1>L)Sort(L,a-1);
if(a+1<R)Sort(a+1,R);
}
冒泡排序
冒泡排序是将大的数一个一个swap上去,是稳定的算法,但是比较慢
时间复杂度O(n^2)
空间复杂度O(n)
是否稳定:稳定
代码实现:
int* BubbleSort(int* ary, int length){
int i, j, tmp;
for(i=0; i<length-1; i++){
tmp = ary[i];
for(j=length-1; j>i; j--){
if(tmp > ary[j]){
swap(ary[i],ary[j]);
}
}
}
return ary;
}
选择排序
选择排序比较无脑(个人认为),每一次把最小的选出来放在最前面,就实现了排序。
时间复杂度:O(n^2)
空间复杂度:O(n)
代码实现:
for(int i=1;i<=n;i++){
int k=i;
for(int j=i+1;j<=n;j++)
if(num[j]<num[k])k=j;
if(k!=i)t=num[i];num[i]=num[k];num[k]=t;
}
归并排序
归并排序利用了分治的思想,将一个数组切成两半,然后在排序
时间复杂度:O(nlog(n))
空间复杂度:O(n)
是否稳定:稳定
代码实现:
void Merge(int L,int R){
if(L==R)return;
int mid=(L+R)/2;
Merge(L,mid);
Merge(mid+1,R);
int i=L,j=mid+1,k=L;
while(i<=mid&&j<=R){
if(A[i]<=A[j])B[k++]=A[i++];
else{
B[k++]=A[j++];
cnt+=mid-i+1;
}
}
while(i<=mid)B[k++]=A[i++];
while(j<=R)B[k++]=A[j++];
for(k=L;k<=R;k++)A[k]=B[k];
}
堆排序:
堆排序没什么用,个人觉得用stl里面的priority_queue或是multiset都可以满足。但是这排序的想法与实现都是非常重要的
时间复杂度:O(nlog(n))
空间复杂度:O(n)
是否稳定:不稳定
代码实现:
void swap(int &a,int &b){//交换两个数
int t=a;a=b;b=t;
}
void down(int k){
while(2*k<=sz){
int a=2*k;
if(a+1<=sz&&heap[a]>heap[a+1])a++;//找较小的儿子
if(heap[k]>heap[a])swap(heap[k],heap[a]);//交换
else break;
k=a;//往下走
}
}
//初始化堆得时候,可以把n/2到1的每个元素都down下。
int heap[200005],sz;//sz记录当前堆得大小,也是最后一个元素的下标
int main(){
int i,j,k,n;
scanf("%d",&n);
sz=n;
for(i=1;i<=n;i++)
scanf("%d",&heap[i]);
for(i=n/2;i>=1;i--) down(i);//初始化堆
for(i=1;i<=n;i++){
printf("%d ",heap[1]);
heap[1]=heap[sz--];//用最后一个元素覆盖堆顶,在删除最后一个元素
down(1);//调整堆
}
return 0;
}
/*堆也可以添加元素,原理down类似,用up,把数字添加在heap[++sz]的位置上。
如果父亲节点比当前元素小,就不断向上。*/
void up(int k){
while(k>1){
int a=k/2;//a是父亲节点
if(heap[a]>heap[k])swap(heap[k],heap[a]);
else break;
k=a;
}
}
插入排序
插入排序说的形象点就是像打牌理牌差不多,找第一个比他大的位置,再把数字往后移。
时间复杂度:O(n^2)
空间复杂度:O(n)
是否稳定:不稳定
代码实现:
for(int i=1;i<=n;i++){
int x=a[i];
for(int j=i-1;j>0&&x<a[j];j--)
a[j+1]=a[j];
a[j+1]=x;
}