目录
题目
代码
#include <iostream> using namespace std; const int N = 100010; int a[N], n; void quick_sort(int a[],int l,int r) { if(l>=r)return ; int i=l-1,j=r+1; int x=a[(i+j)/2]; while(i<j) { do(i++);while(a[i]<x); do(j--);while(a[j]>x); if(i<j)swap(a[i],a[j]); } quick_sort(a,l,j),quick_sort(a,j+1,r); } int main() { cin >> n; for(int i = 0; i < n; i ++)cin>>a[i]; quick_sort(a,0,n-1); for(int i=0;i<n;i++)cout<<a[i]<<' '; return 0; }
代码核心思路:
在整个数组中,我们选取数组的中间一个数 x ,然后用两个指针 i 和 j 从左右两边来遍历数组,当i j时,停止遍历,我们需要把所有小于或等于x的数放到左边,把所有大于或等于x的数放到右边(注意:有可能左右两边同时存在等于x的数),这样子我们就把数组分成了两部分,继续递归处理左右两边的数组,当递归到子数组里面只存在一个数的时候,即 i j 的时候return。在处理每一个子数组的时候,我们都会分裂出两个全新的子数组,在这两个全新的子数组里面a[l...i]x,而且a[j...r]x。采用分治的思想
时间复杂度:O(nlongn)
解决以下问题
问题1:
在快排函数quick_sort()函数的while循环语句里面,为什么要用do..while循环来写
while(i<j) { do(i++);while(a[i]<x); do(j--);while(a[j]>x); if(i<j)swap(a[i],a[j]); }
为什么我们不采用下面的代码呢?
while(i<j) { while(a[i]<x)i++; while(a[j]>x)j--; if(i<j)swap(a[i],a[j]); {
如果我们使用while语句:如果出现a[i]=x, a[j]=x的情况,那
while(a[i]<x)i++; while(a[j]>x)j--;
就无法使i往右边走或者使j往左边走,会让程序陷入死循环中
所有我们使用do...while语句来迫使i往右走和j往左走,这也就解释了为什么一开始要把i的值设置成l-1,r的值设置成r+1。每一次递归之后,a[l...i]x,a[j...r]x
问题2:
递归处理两个子数组的时候用到的为什么是j而不是i?
quick_sort(a,l,j),quick_sort(a,j+1,r);
首先我们要知道 j 取值范围是[l...r-1]
首先在while循环的do(j--);while(a[j]>x);里面就决定了 j 一定小于或等于r;当子数组里面就两个数的时候 j 有可能等于 l
那为什么j的最大值为r-1呢?
首先如果子数组里面只有一个数,那直接return掉,我们只考虑子数组里面的数大于1个数的时候。因为我们取的x是a[(i+j)/2],这意味着x是不可能为a[r]的,虽然他们的值有可能相等,但是x不会取到a[r]本身,这也就决定了do(j--);while(a[j]>x);这条语句至少执行两次!
同理 i 的取值范围为[l...r](这里的x取的是a[(i+j)/2])
所以在递归过程中不能出现i+1或者i-1,这也就解释了为什么这里使用j来递归
sj
在这里是满足a[l...j]x,a[j+1...r]x的
分析
分析1
if(i<j)swap(a[i],a[j])的<能能否换成
可以,当i和j相等的时候换了和没换是一样de
分析2
什么时候才能使用i作为quick_sort的分界点?
当x取a[(l+r+1)/2]的时候,可以
原因:此时,i的取值范围是[l+1...r],而j的取值范围是[l...r],所以递归过程中不能出现j-1或者j+1的情况。
分析3
do i++; while(a[i] < x)和do j--; while(a[j] > x) 中不能用a[i] <= x 和 a[j] >= x
如果说a[l..r]里面全是都是相等的数,那会出现越界的情况(i会增加到r+1,后面会不会继续增加还不知道)
分析4
while(i<j)能不能改成while(ij)?
不能。当执行到i=j的时候,a[i-1](如果存在的话)可能小于x,而a[j+1](如果存在的话)可能大于x,本来这个时候应该停止while循环,但是这里是ij所有a[l...i]里面有大于x的数,a[j...r]里面有小于x的数
结尾
如果要以i为分界点来使用quick_sort函数,则只需修改
void quick_sort(int a[],int l,int r)
{
if(l>=r)return ;
int i=l-1,j=r+1;
int x=a[(i+j)/2];//改成a[(i+j+1)/2]
while(i<j)
{
do(i++);while(a[i]<x);
do(j--);while(a[j]>x);
if(i<j)swap(a[i],a[j]);
}
quick_sort(a,l,j),quick_sort(a,j+1,r);//改成quick_sort(a,l,i-1),quick_sort(a,i,r)
}
完结散花,留个赞再走吧^_^