归并排序
使用分治思想,后序遍历,处理好左右后,用两个指针将二者合并。
关键点:使用动态内存定义 的数组,且最后要手动删除,防止内存爆炸。
关键点:动态定义时,当心越界,多来几个。
#include<bits/stdc++.h>
using namespace std;
#define in read()
#define mid ((l+r)>>1)
int in{
int cnt=0,f=1;char ch=0;
while(!isdigit(ch)){
ch=getchar();if(ch=='-')f=-1;
}
while(isdigit(ch)){
cnt=cnt*10+ch-48;ch=getchar();
}return cnt*f;
}
const int N=100003;
void merge(int a[],int l,int r){
if(l>=r)return;
merge(a,l,mid);merge(a,mid+1,r);
int x=r-l+1;
int *temp=new int[x+3];//重点
for(int i=l;i<=r;i++)temp[i-l+1]=a[i];
int i,j;i=l,j=mid+1;int cnt=0;
while(i<=mid&&j<=r){
if(a[i]<a[j]){
temp[++cnt]=a[i++];
}
else{
temp[++cnt]=a[j++];
}
}
while(i<=mid)temp[++cnt]=a[i++];
while(j<=r)temp[++cnt]=a[j++];
for(int k=l;k<=r;k++)a[k]=temp[k-l+1];
delete []temp;//重点
}int n,a[N];
signed main(){
n=in;
for(int i=1;i<=n;i++)a[i]=in;
merge(a,1,n);
for(int i=1;i<=n;i++)cout<<a[i]<<" ";
return 0;
}
堆排序
严格的nlogn。
首先来说明什么是堆(优先队列的一种实现方式):
一棵完全二叉树,在指定优先级的情况下,根节点一定比两个子节点都优先(比如大根堆的任何根节点都比两个子节点大)。
对于一个堆,基本操作包含:插入,删除,调用目前的最优先项。
插入:在树的末尾添加元素,并不断和父节点比较,如果优先级矛盾,就swap。
调用:输出根节点即可。
删除:只支持删除根节点(即优先度最高项),删除后,将最后一个点抓来顶替根节点,并每次和两个儿子中优先级最高的点进行交换(否则小儿子在大儿子上面产生矛盾),换到不能换为止。
复杂度的保证源于完全二叉树的性质。同时,因为是完全二叉树,我们大可以用一个数组来表示这棵树。初始编号1的情况下,u节点左儿子即u * 2,右儿子即u * 2+1。
对于排序而言,不断调用根节点并做删除操作即可。
#include<bits/stdc++.h>
using namespace std;
#define in read()
int in{
int cnt=0,f=1;char ch=0;
while(!isdigit(ch)){
ch=getchar();if(ch=='-')f=-1;
}
while(isdigit(ch)){
cnt=cnt*10+ch-48;ch=getchar();
}return cnt*f;
}
int n;
const int N=100003;
int a[N];
int q[N],tot;
void ins(int x){
q[++tot]=x;int u=tot;
while(u!=1){
if(q[u/2]>x)swap(q[u/2],q[u]);
else break;
u/=2;
}
}
void del(){
swap(q[1],q[tot]);--tot;
int u=1;
while(u*2<=tot){
int v=u*2;
if(v+1<=tot&&q[v]>q[v+1])++v;
if(q[u]<q[v])break;
swap(q[u],q[v]);
u=v;
}
}
signed main(){
n=in;
for(int i=1;i<=n;i++){
a[i]=in;//无效数组,草
ins(a[i]);
}
for(int i=1;i<=n;i++){
printf("%d ",q[1]);del();
}
return 0;
}
快速排序
弱于其余二者。考虑目标升序。
每次选择一个基准数,将小的丢到左边,大的丢到右边,再递归整左右。
类似于中序遍历。
妙处:不用新开数组,自己左右互相覆盖的写法有启发性。
弱点:复杂度有波动,从n到n^2不等。所以建议使用严格nlogn的算法。
#include<bits/stdc++.h>
using namespace std;
#define in read()
#define mid ((l+r)>>1)
int in{
int cnt=0,f=1;char ch=0;
while(!isdigit(ch)){
ch=getchar();if(ch=='-')f=-1;
}
while(isdigit(ch)){
cnt=cnt*10+ch-48;ch=getchar();
}return cnt*f;
}
const int N=100003;
int n,a[N];
void Sort(int l,int r){
if(l>=r)return;
int tp=a[l];
int i=l,j=r;
while(i<j){
while(j>i&&a[j]>tp)--j;
a[i]=a[j];
while(i<j&&a[i]<=tp)++i;
a[j]=a[i];
}a[i]=tp;
Sort(l,i-1);Sort(i+1,r);
}
signed main(){
n=in;for(int i=1;i<=n;i++)a[i]=in;
Sort(1,n);
for(int i=1;i<=n;i++)printf("%d ",a[i]);
return 0;
}