快排的核心思想——分治
分治:分治法是一种很重要的算法。字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。
理解分治后咱就进入正题
简单来说就是先取一个值,其他值如果比这个值小就丢到这个值左边,如果比这个值大就丢到这个值右边
1.先确定分界点:有很多种分界法,但个人觉得最左边、最右边、和中间(中间指的就是上面说的先取的那个值)这种分界法比较好理解
2.最左边从左往右依次遍历,最右边从右往左依次遍历,遍历过程将遍历的值与中间那个值比较大小,如果值在合适的位置就往下遍历(合适指的是比如这个值比先取的那个值小,而恰好它就在先取的那个值的左边,这个时候就不用管他了,直接遍历下一个值),如果从左往右遍历发现有数不在合适的位置,那就去找一个从右往左遍历不在合适位置的数,它俩位置交换一下,这不就是各取所需,然后一直接着这个方法,直到从左往右的遍历和从右往左的遍历相碰时候,就将这一串数分成两部分,左边都是小于先取的那个数,右边都是大于先取的那个数
int i = l - 1;//l指的是最左边,至于为什么要先减去一个1,是因为下面用do-while
int j = r + 1;//r指的是最右边,加1的原因同上
int x = q[(l+r+1)/2];//这是取中间的点
while (i < j)
{
do { i++; } while (q[i] < x);
do { j--; } while (q[j] > x);
if (i < j)swap(q[i], q[j]);
}
3.(这一步用递归解决问题)既然一串数可以分为两部分,那么第一部分也可以分为两部分,再利用上面的方法不就可以将第一部分又分为两部分,这两部分也是满足右边的数都大于左边,就这样一直分下去刚开始的两部分中的左边部分不久排好了顺序,按照相同的方法把右边部分排好,那就大功告成了
完整代码:
#include<iostream>
using namespace std;
const int N = 1e6 + 10;
int q[N];
int n;
void quick_sort(int q[], int l,int r)
{
if (l >= r)return;
int i = l - 1;
int j = r + 1;
int x = q[(l+r+1)/2];
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()
{
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> q[i];
}
quick_sort(q, 0, n - 1);
for (int i = 0; i < n; i++)
{
cout << q[i] << " ";
}
system("pause");
return 0;
}