今天了解了一下快速排序算法,写个博客巩固一下。快速排序有很多种,今天只讲一种。
快速排序采用了分治法来实现排序,但是我觉得菜鸟教程里面的“挖坑+分治”更加全面。如果我们要对下面的数组num进行排序。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
57 | 78 | 45 | 66 | 12 | 76 | 23 | 89 | 32 | 56 |
设置基准数
我们取第一个数为基准数,int x=num[0]=57;
再设置两个变量待会来操作数组元素
int i=0,j=9;
接下来我们要做的是
1.将数组中比基准数小的元素放在基准数前面
2.将数组中比基准数大的元素放在基准数后面
3.将基准数左右两边的区间重复进行第一步和第二步,直到左右两区间只有一个数。
这里用挖坑来比喻讲解起来会比较好理解一点。首先在int x=num[0];
取出基准值这一步中我们就开始挖坑了,就是在数组的第一个元素这里挖了个坑。那么接下来我们就要填坑了,我们要从数组的后面往前面找,找到一个比基准值小的元素,把他挖出来,填到我们刚才挖的坑中。刚刚的坑被填上后我们就不需要再填它了,所以要向后移一位,比如在这里我们就把num[9]的56挖出来填到num[0]里面,这一步是保证基准数右边的元素比基准数小。下面是代码
while (i<j&&num[j] >= x)//从后往前找
j--;
if (i < j) {
num[i] = num[j];//填坑
i++;//向后移一位
}
但是这样我们又产生了新的坑,所以接下来我们要从前往后找,用数组里比基准数大的元素填上新坑。同样的,刚刚的坑被填上后我们就不需要再填它了,所以要向前移一位,这一步是保证基准数右边的元素比基准数大。
while (i < j&&num[i]<x)//从前往后找
i++;
if (i < j) {
num[j] = num[i];//填坑
j--;//向前移一位
}
这样变量i和j就一直往前和往后移动,一直移动到i和j相等时停止移动,i和j停止移动的位置,就是基准数的最终位置,所以完整代码如下:
int AdjustArray(int *num, int l, int r) {
int i = l;
int j = r;
int x = num[l];
while (i<j)
{
while (i<j&&num[j] >= x)//从后往前找,没有找到比x小的就继续移位
j--;
if (i < j) {
num[i] = num[j];//填坑
i++;//向后移一位
}
while (i < j&&num[i]<x)//从前往后找,没有找到比x大的就继续移位
i++;
if (i < j) {
num[j] = num[i];//填坑
j--;//向前移一位
}
}
num[i] = x;//当i和j相等时跳出循环,其位置为基准数位置
return i;
}
void quicksort(int *num, int l, int r) {
if (l<r) {
int i = AdjustArray(num, l, r);
quicksort(num, i + 1, r);//递归来对基准数的右边区间进行排序
quicksort(num, l, i - 1);//递归来对基准数的左边区间进行排序
}
}
AdjustArray函数是返回基准数的位置,我们这时只进行了一次排序,这还没完,因为这时数组是这样的
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
56 | 32 | 45 | 23 | 12 | 57 | 76 | 89 | 66 | 78 |
我们看到只是保证了基准数57的左边都比57小,右边都比57大。所以还要对基准数的左边和右边区间重复上述排序过程,直到各区间只有一个数,这里用递归实现。
这个快速排序方法我也是看菜鸟教程学会的,我只是用自己的话总结了一下。快速排序还有很多种,等我后面慢慢学习后再写成博客分享给大家。