一、快速排序原理
快速排序(Quicksort)是对冒泡排序算法的一种改进,快速排序的思考方式与归并排序类似,都是二分、分治的思想。
快速排序的基本思路如下:
- 确定分界点:左端点left、右端点right或者选取中间点(left+right)/2,相比而言中间点鲁棒性更好,当然也可以用算法随机选取分界点,此处只介绍简单的分界点选取方法;
- 调整区间:把比分界点小的数移到左边,把比分界点大的数移到右边;
- 递归处理左右两段
1、3没有什么难度,重点在于2,如何把数据按照分界点移到左右两边。这里提供一个双指针思想的模板,选取i、j两个指针(i = left - 1 j = right + 1),每次先加减位置再判断大小,所以i和j初始化要比left和right大一点。
刚开始q[i]<x、q[j]>x,i和j不断向中间移动,当条件不满足时退出循环。此时q[i]>=x且q[j]<=x,调用swap()函数将q[i]和q[j]交换。while循环结束后, q[l..j] ≤x,q[j+1..r]≥x。
举个例子:数列(3、1、2、3、5),设分界点为3。
快速排序的代码模板如下:
void quick_sort(int q[],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);//当前q[i]<x,i继续往右边走
while(q[--j]>x);//当前q[j]>x,j继续往左边走
if(i<j) swap(q[i],q[j]);
}
//递归处理左右两段
quick_sort(q,l,j);
quick_sort(q,j+1,r);
}
二、第k个数
题目描述
给定一个长度为 n 的整数数列,以及一个整数 k,请用快速选择算法求出数列从小到大排序后的第 k个数。
输入格式
第一行包含两个整数 n 和 k。
第二行包含 n个整数(所有整数均在 1∼1000000000 范围内),表示整数数列。
输出格式
输出一个整数,表示数列的第 k小数。
数据范围
1≤n≤100000,
1≤k≤n题目链接
这是一个非常朴素的模板题目,也没什么好分析的,以下是快速排序实现的代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e7+10;//两道题题目不一样,注意数据范围
int n;
int q[N];
void quick_sort(int q[],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(q,l,j);
quick_sort(q,j+1,r);
}
int main()
{
int i,k;
scanf("%d%d",&n,&k);
for(i=0;i<n;i++) scanf("%d",&q[i]);
quick_sort(q,0,n-1);
printf("%d ",q[k-1]);//注意是从0还是从1开始数
return 0;
}
快速排序的时间复杂度为O(),在洛谷的这题中不用O2优化的话会超时,以下为利用快排思想实现的时间复杂度O(n)做法代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 5000010;
int n,k;
int q[N];
void quick_sort(int q[],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]);
}
//递归处理左右两段
//快排后数组被划分为三块: l<=j<=i<=r
if(k<=j) quick_sort(q,l,j);//在左区间只需要搜左区间
else quick_sort(q,j+1,r);//在右区间只需要搜右区间
}
int main()
{
int i;
scanf("%d%d",&n,&k);
for(i=0;i<n;i++) scanf("%d",&q[i]);
quick_sort(q,0,n-1);
printf("%d\n",q[k]);
return 0;
}