超快的排序——
N种答法
众所周知,在oj里一个重要的算法是排序
入门级的:冒泡、选择、箱、插入
进阶级的:快速、归并、堆、桶
当遇到比较大的数据要排序时,入门级大多都不管用了
冒泡、选择超过时间限制
箱超过空间限制
插入还需要练得恰到好处并且找规律
否则也会超过时间限制
那么这里分享两种排法
目录
1.归并排序
2.堆排序
1.归并排序
思路:
归并排序的基本条件是将两个有序序列合并
那么怎么找到两个有序序列呢?
我们可以用递归二分的方法
当一个序列只有一个元素时
默认它是有序的
然后回到这个回溯的过程
将两个有序序列合并
最终合并成一个有序序列
将答案输出
#include<iostream>
using namespace std;
int a[100005],c[100005];
void merge(int l,int r)
{
if(l>=r) return ;//当他只剩下一个或不及一个元素时默认有序,返回
int s=l,mid=(l+r)/2,x=l,y=mid+1;//二分的mid
merge(l,mid);//回溯
merge(mid+1,r);
//此时回溯结束,默认a数组前面到mid有序,mid+1到结束有序
while(x<=mid&&y<=r)//开始合并前后,x和y是指针
{
if(a[x]>a[y])//如果前面的大于后面,取前面
{
c[s]=a[x];
x++;//指针向后挪一位
}
else//否则取后面
{
c[s]=a[y];
y++;
}
s++;
}
while(x<=mid)//如果前面还有未取的全部放到后面
{
c[s++]=a[x];
x++;
}
while(y<=r)//如果不是前面就是后面
{
c[s++]=a[y];
y++;
}
for(int i=l;i<=r;i++) a[i]=c[i];//把c数组赋值回a数组
}
int main()
{
int n,i;
cin>>n;
for(i=1;i<=n;i++) cin>>a[i];
merge(1,n);//开始排序
for(i=n;i>=1;i--) cout<<a[i]<<" ";
return 0;
}
2.堆排序
堆排序原理为把数组看做一个堆
先建设一个有序的堆
然后把堆顶的值取出
放置ans数组
把堆顶移除
然后维护下一个堆顶
如此循环
#include <iostream>
using namespace std;
int a[100005],n,s;
void up(int x)
{
if(x==1||a[x]<=a[x/2]) return ;//如果是堆顶或是已达成顺序,返回
swap(a[x],a[x/2]);//否则把父节点和子节点交换
up(x/2);//往上接着换
return ;
}
void down(int x)
{
int l=2*x,r=l+1,da=x;
if(l<=s&&a[l]>a[da]) da=l;//将da替换成最大值
if(r<=s&&a[r]>a[da]) da=r;
if(da!=x)
{
swap(a[x],a[da]);//如果da改变了,交换
down(da);//继续
}
}
int main(int argc, char** argv)
{
int i;
cin>>n;
s=n;//当前的堆大小
for(i=1;i<=n;i++)
{
cin>>a[i];//输入数组,建造最小堆
up(i);
}
for(i=n;i>1;i--)
{
swap(a[1],a[s]);//先将堆顶和堆底交换
s--;//堆的大小减一
down(1);//维护新堆顶
}
for(i=1;i<=n;i++) cout<<a[i]<<" ";
return 0;
}
不见不散,咱们下期再见~~