快速排序的基本思路:找一个基准元素,对数组进行调整,调整的标准是,这个基准元素的左边存放的都是比这个元素小的,右边都是比这个元素大的。然后分而治之,对左右两边的子数组利用同样的规则调整,调整到每一个子数组中都只有一个元素时结束。
基本思想很简单,主要是理解如何在确定基准元素之后,对数组(子数组)进行调整,下面举个例子,用“挖坑填坑”(拆了东墙补西墙)的比喻来理解一次调整的过程。
一个无序数组:[4, 3, 7, 5, 10, 9, 1, 6, 8, 2]
1. 随便先挖个坑,就在第一个元素(基准元素)挖坑,挖出来的“萝卜”(第一个元素4)在“篮子”(临时变量)里备用。挖完之后的数组是这样:[ 坑, 3, 7, 5, 10, 9, 1, 6, 8,2]
2. 挖右坑填左坑:从右边开始,找个比“萝卜”(元素4)小的元素,挖出来,填到前一个坑里面。填坑之后:[ 2, 3, 7, 5, 10, 9, 1, 6, 8,坑]
3. 挖左坑填右坑:从左边开始,找个比“萝卜”(元素4)大的元素,挖出来,填到右边的坑里面。填坑之后:[ 2, 3,坑, 5, 10, 9, 1, 6, 8, 7]
4. 挖右坑填左坑:从右边开始,找个比“萝卜”(元素4)小的元素,挖出来,填到前一个坑里面填坑之后:[ 2, 3, 1, 5, 10, 9,坑, 6, 8, 7]
5. 挖左坑填右坑:从左边开始,找个比“萝卜”(元素4)大的元素,挖出来,填到右边的坑里面填坑之后:[ 2, 3, 1,坑, 10, 9, 5, 6, 8, 7]
6. 挖右坑填左坑:从右边开始,找个比“萝卜”(元素4)小的元素,挖出来,填到前一个坑里面,这一次找坑的过程中,找到了上一次挖的坑了,说明可以停了,用篮子里的的萝卜,把这个坑填了就行了,并且返回这个坑的位置,作为分而治之的中轴线。填坑之后:[ 2, 3, 1, 4, 10, 9, 5, 6, 8, 7]
上面的步骤中,第2,4, 6其实都是一样的操作,3和5的操作也是一样的。
代码如下:
int _qucikly_sort(int arr[], int low, int high) {
int pivot = arr[low]; //挖第一个坑,把“萝卜”放进篮子
while(low<high) { //开始循环挖坑填坑
//如果low等于high,说明找坑的过程中,找到了上一次挖的坑,因此可以停止了
while(low<high && arr[high]>=pivot) //从右边往左边找填坑的元素(比pivot小的元素)。 2,4,6的过程
--high;
arr[low] = arr[high]; //将找到之后,挖出来,填到左边的坑里
while(low<high && arr[low]<=pivot) //从左边往右边找填坑的(比pivot大的元素)。3,5的过程
++low;
arr[high] = arr[low];//找到之后,填到右边的坑里
}
arr[low] = pivot; //篮子里的“萝卜”填到坑里
return low;//返回这个坑的位置,作为分而治之的中轴
}
分而治之的代码:
void quickly_sort(int arr[], int low, int high) {
if (low < high) {
int pivot = _qucikly_sort(arr, low, high);
quickly_sort(arr, low, pivot-1);
quickly_sort(arr, pivot + 1, high);
}
}
测试代码:
#include <stdio.h>
#include <stdlib.h>
void display(int arr[], int len) {
for(int i = 0; i < len;i++)
printf("%d ", arr[i]);
printf("\n");
}
int main() {
int arr[] = {4, 3, 7, 5, 10, 9, 1, 6, 8, 2};
quickly_sort(arr, 0, sizeof(arr)/sizeof(int) - 1);
display(arr, sizeof(arr)/sizeof(int));
return 0;
}