一、原理讲解
快速排序的核心思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
简单的说法,就是设置一个基准,将无序数组的数据分隔成两部分,基准左边的数据都小于基准,基准右边的数据都大于基准。然后不断设置基准与参与排序的数据个数进行排序,直至整个数组为一个有序数组。
假定有一个无序整型数组:int arr4[10] = {11, 7, 0, 1, 5, 8, 10, 31, 2, 19};
下面详细讲解快速排序的实现过程:
第一步,选取第数组第一个元素作为基准并且将值保存到par变量中,图中红框的元素。设置参与排序的数组下标start和end。
第二步,取end对应的元素与par进行比较,若 arr[end] < par ,则给start对应的元素赋值arr[end](arr[start] = arr[end]), 否则end--(end前移)。其中arr[end] > par 所以, end--,end前移。得到如下结果:
此时继续取end对应的元素与par进行比较,arr[end] < par ,所以给arr[start]赋值arr[end],(arr[start] = arr[end])。得到如下结果:
此时取start对应的元素与par进行比较,若arr[start] > par,则给arr[end]赋值arr[start],(arr[end] = arr[start]),否则start++,将start后移。
这里start = 0时,arr[start]没有小于par,所以将start后移,当start = 2时,arr[start]没有小于par,所以将start后移....
当start = 7时,arr[start] > par,所以arr[end] = arr[start]。结果如下:
此时切换回取end对应的数据进行比较。
此时我们将end前移之后,我们发现start = end。这会第一次排序完成,我们将arr[start] 赋值par,(arr[start] = par)。
得到的结果如下:
这里我们能清晰的看到一开始选定的基准点11,他左边的数据都小于11,右边的数据都大于11。
后面我们将循环以上步骤,直至整个数组为有序数组为止(start >= end),注意每轮排序都需要重新设置参与排序的数组元素起始位置和结束位置。直至整个所有参与排序的子数组都满足(start >= end)后结束排序。
这里我们得到结论:
1.先从队尾开始向前扫描且当start < end时,如果arr[end] > par,则end--(end前移),但如果arr[end] < par,则将end的对应元素的值赋值给arr[start],即arr[start] = arr[end],同时要转换数组扫描的方式,即需要从队首开始向队尾进行扫描了。
2.同理,当从队首开始向队尾进行扫描时,如果arr[start] < par,则start++(start后移),但如果arr[start] > par了,则就需要将start对应元素的值赋值给end对应的元素,即arr[start] = arr[end],同时将数组扫描方式换为由队尾向队首进行扫描。
3.不断重复1和2,指导start >= end时(其实是start = end),start或end的位置就是该基准数据在数组中的正确索引位置。
这里有一点我们需要注意,每次排序完,进行第二次排序时,排序的数据个数只是基准左边或者右边的数据。如上个例子,第一轮排序完之后进行第二次排序,我们进行排序的数组元素就只有arr[0]到arr[6],因为arr[0]到arr[6]的数据都小于基准值,直至参与排序的左边数组对应的star = end。
然后我们开始排序基准右边的数组。排序步骤与上相同。
如下图是该数组每轮排序后的结果:
二、具体代码
/*
函数名:int QuickSort(int data[], int start, int end);
函数功能:使用快速排序的方法,将数组按从小到大排序
函数参数:
data[]:数组首地址
start:数组首个元素下标
end:数组最后一个元素下标
函数返回值:
函数成功排序数组返回0,失败返回-1
*/
int QuickSort(int data[], int start, int end)
{
int i = start;
int j = end;
int par = data[start]; //选定基准
if (start >= end) //当start >= end 结束该轮循环
return -1;
while (i < j)
{
//在i < j 的前提下,找到par > data[j] 的数据,然后就将data[j]的值赋给data[i]
while (i < j && par <= data[j]) //此处若是 par < data[j] 遇到两个相同的数则会排序失败
j--;
data[i] = data[j];
//在i < j 的前提下,找到par < data[i] 的数据,然后就将data[i]的值赋给data[j]
while (i < j && par >= data[i]) //此处若是 par > data[i] 遇到两个相同的数则会排序失败
i++;
data[j] = data[i];
}
data[i] = par; //将基准值存放到对应的位置
QuickSort(data, start, i - 1); //递归排序左子数组 并且更改参与排序的数组元素
QuickSort(data, i + 1, end); //递归排序右子数组 并且更改参与排序的数组元素
return 0;
}
这里程序使用的递归调用,若对递归不熟练的话,读者可以查询一下,使用栈实现快速排序的代码,所有的递归函数都可以使用栈实现。
仓促成文,不当之处,尚祈方家和读者批评指正。联系邮箱1772348223@qq.com