一、原理
选一个基准数,通常选需要排序数组的第一个元素,将该基准数从两端开始比较,找到从左边起比此基数大的数,从右边起比此基数小的数,然后交换两数,两端相遇后一轮截止,相遇的位置就是基准数的正确位置,且基准数左边都小于此基准数,右边都大于此基准数。所以,一次排序过后,能找到第一个元素的正确位置,且把数组分为左右两个部分。然后采用递归的思想,左右两边重复调用第一次排序的函数,不断分割数组,直至所需要排序的数组长度为0。
用一幅图简单表示一轮排序:
①选取左端第一个数为基准数
②从数组左右两端开始与基准数比较
③找到左端比基准数大的数,右端比基准数小的数
④交换i,j位置对应的两数
⑤交换完后继续往中间靠,可见元素9,4也需要交换位置
⑦最后i,j在中间相遇,相遇位置即基准数6的正确位置,将该基准数与i,j相遇所在位置交换
二、C++代码实现
#include<iostream>
#include<string>
using namespace std;
void quick_sort(int* arr, int begin, int end) {
if (begin >= end) {
return;
}
int temp = arr[begin];
int i = begin;
int j = end;
while (i != j) {
while (arr[j] >= temp && i<j) {
j--;
}
while (arr[i] <= temp && i<j){
i++;
}
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
arr[begin] = arr[i];
arr[i] = temp;
quick_sort(arr, begin, i - 1);
quick_sort(arr, i + 1, end);
}
void main() {
int arr[10] = { 7,5,3,4,1,2,10,8,6,9 };
quick_sort(arr, 0, 9);
cout << "quick_sort:" ;
for (auto i : arr) {
cout << i << " ";
}
}
该代码首先定义快速排序函数,无返回值,需传入数组指针,排序的起始位置和结束位置。
函数内定义一个temp保存基准数,i,j表示从两端开始移动,只要i,j不相等就通过++或--逐渐靠拢,直至相遇,中间需要将左端比基准数大的数与右端比基准数小的数交换。
相遇后再将相遇位置与基准数交换。
以i或j为界分为左右两部分,利用递归分别再进行排序,quick_sort(arr, begin, i - 1)负责对左边部分排序,quick_sort(arr, i + 1, end)负责对右边部分排序。
三、思考
在自己写代码的时候有一个疑问,为什么递归的终止条件可以是begin>end,>=,而不是==?
按道理来说,左端排序开始位置是0,结束位置通过i-1不断减小,两个相等的时候表示长度为一了,终止就行,右端也是一样,一个循序渐进的过程不就是从大于到等于再到小于吗?等于的时候就该终止了。
实际上,终止是在下一次递归实现的。考虑最后一次排序,就是当找到的i,j与begin相等时,后面就不用排了,所以在后面递归的quick_sort(arr, begin, i - 1)应该终止,而此时begin已经与i相等了,所以终止条件应该是begin == end+1,也就是begin>end。写begin == end+1也能通过测试。