先简后难,先简后难
重要的事情说三遍~
续
快速排序
快速排序,顾名思义,它的排序算法执行起来十分的快
首先要知道,快速排序的算法是基于递归函数的基础之上的。不懂什么是递归函数?也没关系,
递归,也就是名字听起来比较专业罢了
先给定一组数据:{6 , 2 , 5 , 8 , 4 , 7 , 3 , 9,1}
- 我们先指定一个基准数(就是用来参照的数),方便起见,我们用第一个数6作为基准数
接下来,需要将比6小的数都放在6的左边,比6大的数都放在6的右边
我们需要将数组以6为基准,分为两半,左一半比6小,而右一半比6大。想一想我们之前所用到的
冒泡排序,交换排序......
- 方法其实很简单,分别从初始序列两端开始探测,先从右向左找到第一个小于6的数(想一想为什么是先从右往左找),再从左向右找到一个大于6的数,然后交换它们。我们可以使用两个变量i , k 来记录遍历的下标。代码如下(我们先忽略i,k的初始化问题)
for(; k>i && array[k] >= 6; --k); for(; k>i && array[i] <= 6; ++i);
一旦找到,然后停下,开始交换元素值
t = array[i]; array[i] = array[k]; array[k] = t;
第一次交换结果如下
然后重复上述过程,直至i,k都指向了同一元素,说明两指针已经相遇,一轮交换已经完成
结果如下
(倘若我们不加此条件限制的话,i遍历至最后,k遍历至最前,同样的数会发生两次交换,那就是相当于什么都没有做!)
这时,不难发现所在的位置正好适合我们最初想要的位置(左边的元素都不大于6,右边元素大于6),我们只要交换i对应的元素值和基准元素,这样,一轮交换就正式完成了,一轮之后,结果如下
接下来,我们就要用到刚才提起过的递归知识了。现在,数组中的元素我们可以这样看待:
{不大于6的数组}, 6, {大于6的数组};然后,我们对{不大于6的数组}进行上述步骤,对{大于6的数组}也进行上述步骤。但如何确定这个大数组中的子数组呢?
下标!成为了我们的必用品,所以,在定义函数时,也应该注意,范例如下
void QuickSort (int array[], int lowIndex, int highIndex);
还记得我们先前说暂时忽略初始化问题吗?
因为每一次调用快速排序的函数时,传入的lowIndex,与highIndex都不同,所以要有所顾忌
int i = low; int k = high; int t; int tmp = array[low];
i,k用于遍历,在这里初始化了,就不必在先前的for中初始化,t为辅存空间,用于元素值的交换
tmp 保存的基准数啦
在一个函数中的代码块调用自己,就是递归函数,代码如下
QuickSort(array, low, i-1); QuickSort(array, i+1, high);
基准元素6的下标就是i,所以我们只需调用函数处理,{不大于6的数组}、 {大于6的数组}就OK
不要忘记,递归一定是要向已知方向递归的。当我们发现,lowIndex >= highIndex 的时候,说明传入的数组元素只有一个甚至说没有了,那还排序干嘛?! 直接return啊~
if(low >= high) { return ; }
整体代码如下
void QuickSort (int array[], int lowIndex, int highIndex) { int i = lowIndex; int k = highIndex; int t; int tmp = array[lowIndex]; if(lowIndex >= highIndex) { return ; } while(i < k) { for(; k>i && array[k]>=tmp; --k); for(; k>i && array[i]<=tmp; ++i); if(i < k) { t = array[i]; array[i] = array[k]; array[k] = t; } } array[lowIndex] = array[i]; array[i] = tmp; QuickSort(array, lowIndex, i-1); QuickSort(array, i+1, highIndex); }
ps:楼主能力有限,一次写不完所有排序哈,见谅~