归并排序及快速排序
两种常用的排序方式
1.归并排序
核心思想:分治
①递归排序 \(left\) \(right\) 此时前后两边都有序了
②归并排序 将两边最小的一个放到一个新数组中
//具体动图在这
https://www.runoob.com/wp-content/uploads/2019/03/mergeSort.gif
//核心代码
int q[N],tmp[N];
int merge_sort(int q[],int l,int r){
if(l>=r) return ;
int mid=(l+r)>>1;
merge_sort(q,l,mid);
merge_sort(q,mid+1,r);
int k=0,i=l,j=mid+1;
while(i<=mid&&j<=r){
if(q[i]<=q[j]) tmp[k++]=q[i++];
else tmp[k++]=q[j++];
}
while(i<=mid) tmp[k++]=q[i++];
while(j<=r) tmp[k++]=q[j++];
for(int i=l,j=0;i<=r;i++,j++) q[i]=tmp[j];
}
//一定要用手模拟一遍,用指针走一遍
归并排序求逆序对
在每次比较时如果发现大于的直接加上mid-i+1即可
具体去看其他博客
#include<iostream>
using namespace std;
int a[500010];
int tmp[500010];
int n;
long long ans=0;
void merge_sort(int q[],int l,int r){
if(l>=r) return;
int mid=(l+r)>>1;
merge_sort(q,l,mid);
merge_sort(q,mid+1,r);
int i=l,j=mid+1;
int k=0;
while(i<=mid&&j<=r){
if(q[i]>q[j]) tmp[k++]=q[j++],ans+=mid-i+1;
else tmp[k++]=q[i++];
}
while(i<=mid) tmp[k++]=q[i++];
while(j<=r) tmp[k++]=q[j++];
for(int u=l,v=0;u<=r;u++,v++) q[u]=tmp[v];
}
signed main(){
cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
merge_sort(a,0,n-1);
printf("%lld" ,ans);
}
2.快速排序
核心思想:分治
①确定分界点:x可以取q[l],q[(l+r)>>1],q[r]
②调整范围,把小于x的放在左边,大于x的放在右边(重点)
③递归处理左右两段
方法一:
①开两个额外的数组(好理解,但是很浪费空间)
②q[ l~r ] 枚举区间内的每一个数,然后把每一个数放在相应的数组中
// a->b 表示把a赋值给b
//a指的是小于x的数放在的区间,b是大于x的
int k1=0,k2=0;
int x=q[l];
for(int i=l;i<=r;i++){
if(q[i]<=x) q[i]->a[k1++];
if(q[i]->x) q[i]->b[k2++];
}
方法二(常用):
①用两个指针i,j
②当i>=x 时移动j,然后找到符合条件的j,交换i,j,最后处理剩余的
void quick_sort(int q[],int l,int r){
if(l>=r) return;
int x=q[l];
int i=l-1,j=r+1;
while(i<j){
do i++; while(q[i]<x);
do j--; while(q[j]>x);
if(i<j) swap(q[i],q[j]);
}
//如果这个数在自己该在的区间(指的是大于或小于x),就处理下一个,直到处于不应该时的位置时停止,双方进行交换
quick_sort(q,l,j);
quick_sort(q,j+1,r);
}
以上两种排序方式一定要三思且用手模拟一遍
归并排序的最经典的应用是求逆序对
快速排序的话可以去看看洛谷P1923(大力推荐,提交时别吸氧)
//千里之行,始于足下