快速排序
- 确定中间点x=q[(l+r+1/2)]
- 定义首尾指针i=l-1、j=r+1;每次与中间点x比较,轮流向中间进发,彼此交换元素,直至相遇
- 对各个区间段进行递归,停止条件:l>=r;
注:scanf()相较cin更快;
代码如下:
#include<iostream>
using namespace std;
const int N = 1e5+1;
int q[N];
int n;
void quick_sort(int q[],int l,int r)
{
if(l>=r) return;
int x=q[(l+r+1)/2],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]);}
}
quick_sort(q,l,i-1);
quick_sort(q,i,r);
}
int main()
{
//input
scanf("%d",&n);
for(int i =0;i<n;i++)
{
scanf("%d",&q[i]);
}
//sort
quick_sort(q,0,n-1);
//output
for(int i=0;i<n;i++) printf("%d ",q[i]);
return 0;
}
快速选择求第k个数
- 在快速排序基础上,求第k个或第k-sl个数
- 若k<左边区间长度sl,则一定在左边区间,只需对左边递归
若k>左边区间长度sl,则一定在右边区间,只需对右边递归,求解第k-sl大的数 - 递归结束条件:l==r,q[l]==q[r]即为答案
#include<iostream> using namespace std; const int N=1e5+10; int n,k; int q[N]; int quick_select(int l,int r,int k) { if(l==r) return q[r]; int x=q[l], 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]); } int sl=j-l+1; if(k<=sl) return quick_select(l,j,k); return quick_select(j+1,r,k-sl); } int main() { //input cin>>n>>k; for(int i=0;i<n;i++)scanf("%d",&q[i]); //select int s=quick_select(0,n-1,k); //output cout<<s<<endl; return 0; }
归并排序
- 基本思想:分治。按下标划分中间点。分别将左右区间排序好后再合并,难点在合并
- 确定中间点mid=l + r >>1;划分左右区间[L,R]={[l,mid],[mid+1,r]}
- 分别对左右区间进行递归调用merge_sort
- 将两个有序序列合并成一个有序序列
注:算法的时间复杂度为:O(nlogn),每层为n,一共logn层
代码如下:
#include<iostream>
using namespace std;
const int N = 1e5+10;
int n,k;
int q[N],temp[N];
void merge_sort(int q[],int l,int r)
{
//stop condition
if(l>=r)return;
//递归
int mid=l + r>>1;
merge_sort(q,l,mid);merge_sort(q,mid+1,r);
//merge
int i=l,j=mid+1;
k=0;
while(i<=mid&&j<=r)
if(q[i]<=q[j])temp[k++]=q[i++];
else temp[k++]=q[j++];
while(i<=mid)temp[k++]=q[i++];
while(j<=r)temp[k++]=q[j++];
for(int i = l,j=0;i<=r;i++,j++)q[i]=temp[j];
}
int main()
{
//input
scanf("%d",&n);
for(int i=0;i<n;i++)scanf("%d",&q[i]);
//merge_sort
merge_sort(q,0,n-1);
//output
for(int i=0;i<n;i++)printf("%d ",q[i]);
return 0;
}