排序
summary:
用好\(sort\)万事大吉
可以康康归并排序逆序对——当然还是觉得树状数组求逆序对更简单
冒泡排序
原理
冒泡排序是一种交换排序,它的基本思想是:两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。
https://zhuanlan.zhihu.com/p/61094267
复杂度最好\(O(n)\)——本身有序
最差\(O(N^2)\)——本身逆序
优化
例题
https://www.luogu.com.cn/problem/P4378
Description
进行多少次冒泡排序
Solution
转载自https://www.cnblogs.com/Hs-black/p/11626111.html
博客后还有别的证明方法
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=4e6+10;
inline int read() {
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,m,cnt;
int b[N],c[N];
pair<int,int>a[N];
void update(int x){
for(;x<=N;x+=x&(-x))
c[x]++;
}
int query(int x){
int res=0;
for(;x;x-=x&(-x))
res+=c[x];
return res;
}
int ans;
bool cmp(pair<int,int> a,pair<int,int> b){
return a.second<b.second;
}
int main(){
n=read();
for(int i=1;i<=n;i++) a[i]=make_pair(read(),i);
sort(a+1,a+1+n);
for(int i=1;i<=n;i++) a[i].first=i;
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++){
update(a[i].first);
ans=max(ans,i-query(a[i].first));
}
printf("%d\n",ans+1);
return 0;
}
直接插入排序
类似于斗地主整理手牌
希尔排序
没啥用吧
快速排序
常用的
一趟排序基准元素就在它正确的位置,然后递归处理它前面的和后面的,
void qsort(int a[],int l,int r){
if((l<r){
int i=l,j=r,x=a[l];
while(i<j){
while(i<j&&a[j]>=x) j--;
if(i<j) a[i++]=a[j];
while(i<j&&a[i]<x) i++;
if(i<j) a[j--]=a[i];
}
a[i]=x;
qsort(a,l,i-1);
qsort(a,i+l,r);
}
}
一般用好\(sort\)就万事大吉
选择排序
直观
归并排序
\(O(nlogn)\)
\[T(n)=2*T(n/2)+n;\\
设m=2^k,k=logm;则有
T(n)=2*T(n/2)+n=2*T(2*T(n/4)+n/2)+n...\\
2^k*T(1)+k*m=m+m*logm;\\
\]
递归树\(log\)层,每层合并是\(n\)
求逆序对
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=1e6;
inline int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n;
long long a[N],c[N],ans;
void merge(int l,int r){
if(l>=r) return;
int mid=(l+r)>>1;
merge(l,mid);
merge(mid+1,r);
for(int i=l;i<=r;i++) c[i]=a[i];
int i=l,j=mid+1;
for(int k=l;k<=r;k++){
if(i>mid) a[k]=c[j++];
else if(j>r) a[k]=c[i++];
else if(c[i]>c[j]) a[k]=c[j++],ans+=mid-i+1;//和j产生的逆序对数量
else a[k]=c[i++];
}
}
int main(){
n=read();
for(int i=1;i<=n;i++)
a[i]=read();
merge(1,n);
printf("%lld\n",ans);
return 0;
}