一、快速排序
核心思想: 把一个序列分为两部分,左半部分所有数均小于等于或大于等于右半部分所有数,递归处理左右两部分
具体步骤: 其中q为一个数组,l为数组的左端点下标,r为数组的右端点下标
确定分界点q[(l+r)>>1]
利用双指针交换调整左右区间,使左区间内数据均小于等于右区间内数据(升序排序),或者使左区间内数据均大于等于右区间内数据(降序排序)
递归处理左右区间[l,j]和[j+1,r]
实现代码:
//main函数里: quick_sort(0,n-1);
void quick_sort(int l, int r)//快排模板
{
if (l >= r) return;//必须 >=
int x = q[l + r >> 1], i = l - 1, j = r + 1;
while (i < j)
{
while (q[++i] < x) ;
while (q[--j] > x) ;
if (i < j) swap(q[i], q[j]);
}
quick_sort(l, j);
quick_sort(j + 1, r);
}
快排的应用:快速选择
简述:求一个序列中第k小的数
分析:
- 大体上套用快排模板
- 区别在于如果k小于等于左半区间的长度,递归处理左半部分;
- 否则,递归处理右半部分
代码实现:
#include<iostream>
using namespace std;
const int N = 100010;
int q[N];
int quick_sort(int l, int r, int k)
{
if (l >= r) return q[l]; //可以==,也可以>=
int x = q[l + r >> 1], i = l - 1, j = r + 1;
while (i < j) {
while (q[++i] < x);
while (q[--j] > x);
if (i < j) swap(q[i], q[j]);
}
int sl = j - l + 1;//sl为左区间元素的个数
if (k <= sl) return quick_sort(l, j, k);
return quick_sort(j + 1, r, k - sl);
}
int main()
{
int n, k;
cin >> n >> k;
for (int i = 0; i < n; ++i) cin >> q[i];
cout << quick_sort(0, n - 1, k) <<endl;
}
二、递归排序
核心思想: 把两个有序且同序的序列,合并为一个有序的序列
具体步骤:
- 确定分界点,把区间
[l,r]
,分为[l,mid]
和[mid+1,r]
- 递归处理 左右区间
[l,mid]
和[mid+1,r]
- 归并,把两个有序的区间合并为一个有序区间
代码实现:
//main函数里: merge_sort(0,n-1);
void merge_sort(int l,int r)//归并模板
{
if(l==r) return ;
int mid=(r+l)/2;
merge_sort(l,mid);
merge_sort(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++];
}
}
while(i<=mid) b[k++]=a[i++];
while(j<=r) b[k++]=a[j++];
for(i=l;i<=r;i++) a[i]=b[i];//a数组存放答案
}
归并的应用:逆序对
逆序对定义:两个数,前者大于后者,则称这两个数为一个逆序对
简述:求一个序列中逆序数的数量(即i<j并且a[i]>a[j])
代码实现:
#include<bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
const int N=5e5+5;
int a[N],b[N];
int merge_sort(int l,int r)
{
if(l>=r) return 0;
int mid=l + r >> 1;
int ret=merge_sort(l,mid)+merge_sort(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++];
ret+=mid-i+1;
}
}
while(i<=mid) b[k++]=a[i++];
while(j<=r) b[k++]=a[j++];
for(i=l;i<=r;i++) a[i]=b[i];
return ret;
}
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int n;
cin >> n;
for(int i=0;i<n;++i) cin >> a[i];
cout << merge_sort(0,n-1) << endl;
return 0;
}