vlambda博客
学习文章列表

快速排序之挖坑法(C语言实现)

我对快速排序的理解

快速排序,是九大排序里面平均性能最好的,是对冒泡排序的改进。其运用了分治的思想,不难理解,但是用编程语言描述的时候会相对来说有点困难。

快速排序的方法

步骤为:
1.挑选基准值:从数列中挑出一个元素,称为“基准”(pivot)
2.分割:重新排序数列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准后面(与基准值相等的数可以到任何一边)。在这个分割结束之后,对基准值的排序就已经完成。
3.递归排序子序列:递归地将小于基准值元素的子序列和大于基准值元素的子序列排序。
递归到最底部的判断条件是数列的大小是零或一,此时该数列显然已经有序。

上面这段话来自维基百科,如果我翻译翻译那就是:先在数列中随便找个数叫做基准数(pivot)。

然后将数列中小于pivot的数放到pivot的前面,把大于pivot的放到pivot的后面。

快速排序之挖坑法(C语言实现)
这样就是一轮排序了,得到的结果就是pivot前面的数字都比pivot小,pivot后面的数字都比pivot要大。然后,我们再用此方法分别将pivot两边的数排一下,其实就是递归了。

快速排序之挖坑法(C语言实现)

难点分析

看到这里,相信你应该已经知道快速排序是怎么一回事了。但是,说的轻巧,但如何用编程语言实现呢?其实是有挺多种方法的,这也就是为什么大家看的快速排序代码有很多版本。
其中,我认为最好理解的是挖坑法。

图解挖坑法

代码实现 (C语言)

/* 每一轮的排序 */
int sort(int arr[], int left, int right)
{   
    /* 选择arr[left]作为新坑,并将此值作为基准保存至pivot*/
    int pivot = arr[left];
    /* 当退出循环的时候,left与right相遇,left==right */
    while (left<right)
    {   
        /* right指针从右往左走,直到遇到比pivot值小的数 */
        while(arr[right] > pivot && left < right) right --;
        /* right指针遇到了比pivot值小的数,将其填入坑中, 此时产生新坑arr[right]*/
        arr[left] = arr[right];
        /* left指针从左往右走,直到遇到比pivot值大的数 */
        while(arr[left] < pivot && left < right) left ++;
        /*
        left指针遇到了比pivot值大的数,
        填入刚才的新坑 arr[right]中
        此时产生新坑arr[left] */

        arr[right] = arr[left];
    }
    /* 跳出循环,left==right,将基准值填入上一步产生的坑arr[left] */
    arr[left] = pivot;
    /* 至此所有坑填补完毕,pivot左边的都比pivot值大,右边反之。返回 pivot的下标*/
    return left;
}

void quick_sort(int arr[], int left, int right)
{   
    /* 递归的条件:如果left小于right表明arr数组至少有两个元素,可以进行排序 */
    if(left<right){
        /* 对arr排序,mid是排序后基准值的下标 */
        int mid = sort(arr, left, right);
        /* 由于mid左边的都比基准值小,mid右边的都比基准值大。
        所以,对mid两边的两部分分别排序 */

        quick_sort(arr, left, mid-1);
        quick_sort(arr, mid+1, right);
    }
}

如果觉得不够优雅,也可以整理成一个函数,多引入俩变量。

void quick_sort(int arr[], int left, int right)
{   
    if(left<right){
        int i=left, j=right;
        int pivot = arr[left];
        while(i<j){
            while(arr[j]>pivot && i<j) j--;
            arr[i] = arr[j];
            while (arr[i]<pivot && i<j) i++;
            arr[j] = arr[i];   
        }
        arr[i] = pivot;
        quick_sort(arr, left, i-1);
        quick_sort(arr, i+1, right);
    }
}

数字是用在线网站随机选取的

end

上面的代码可以作为理解快速排序用,实际上还有挺多小细节可以优化。