快速排序法

快速排序采用的思想是分治思想。

快速排序是找出一个元素(理论上可以随便找一个)作为基准(pivot),然后对数组进行分区操作,使基准左边元素的值都不大于基准值,基准右边的元素值 都不小于基准值,如此作为基准的元素调整到排序后的正确位置。递归快速排序,将其他n-1个元素也调整到排序后的正确位置。最后每个元素都是在排序后的正确位置,排序完成。所以快速排序算法的核心算法是分区操作,即如何调整基准的位置以及调整返回基准的最终位置以便分治递归。

举例说明一下吧,这个可能不是太好理解。假设要排序的序列为

2 2 4 9 3 6 7 1 5 首先用2当作基准,使用i j两个指针分别从两边进行扫描,把比2小的元素和比2大的元素分开。首先比较2和5,5比2大,j左移

2 2 4 9 3 6 7 1 5 比较2和1,1小于2,所以把1放在2的位置

2 1 4 9 3 6 7 1 5 比较2和4,4大于2,因此将4移动到后面

2 1 4 9 3 6 7 4 5 比较2和7,2和6,2和3,2和9,全部大于2,满足条件,因此不变

经过第一轮的快速排序,元素变为下面的样子

[1] 2 [4 9 3 6 7 5]

之后,在把2左边的元素进行快排,由于只有一个元素,因此快排结束。右边进行快排,递归进行,最终生成最后的结果

 

比轴值小的放它的左边,比轴值大的放它的右边,这样最后找的的下标(low==high)就是当前轴值应该在的位置。

每个元素都要当一次轴值

核心代码:

int Partition(int *array, int left, int right)
{
    if (left < right) //递归结束的条件  left==right
    {
        int index = array[left];
        int low = left;
        int high = right;
        while (low < high)
        {
            //从右向左找比轴值小的,找到就放在开始位置
            while (low<high && array[high] >= index)
                high--;
            array[low] = array[high];

            //从左向右找比轴值大的,找到就放在末尾
            while (low<high && array[low] <= index)
                low++;
            array[high] = array[low];
        }
        array[low] = index;  //轴值放在它应该在的位置

        Partition(array, left, low - 1);  //对低子表递归排序
        Partition(array, low + 1, right);    //对高子表递归排序
    }
    return 0;
}

 

void QuickSort(int array[], int len)
{
    Partition(array, 0, len - 1);
}

完整的代码:

#include <stdio.h>
#include <stdlib.h>

int Partition(int *array, int left, int right)
{
    if (left < right) //递归结束的条件  left==right
    {
        int index = array[left];
        int low = left;
        int high = right;
        while (low < high)
        {
            //从右向左找比轴值小的,放在开始位置
            while (low<high && array[high] >= index)
                high--;
            array[low] = array[high];

            //从左向右找比轴值大的,放在末尾
            while (low<high && array[low] <= index)
                low++;
            array[high] = array[low];
        }
        array[low] = index;

        Partition(array, left, low - 1);  //对低子表递归排序
        Partition(array, low + 1, right);    //对高子表递归排序
    }
    return 0;
}

void QuickSort(int array[], int len)
{
    Partition(array, 0, len - 1);
}


void main()
{
    int a[] = { 1, 5, 2, 4, 2 };
    int len = sizeof(a) / sizeof(a[0]);
    QuickSort(a, len);
    for (int i = 0; i<len; i++)
        printf("%d\n", a[i]);
    system("pause");

}
View Code

 

 

最坏时间复杂度为  O(n²),平均时间复杂度为O(nlogn)。

空间复杂度,需要一个栈空间来实现递归。空间复杂度为O(logn).

 

基准关键字的的选择

基准关键字的选择决定了快速排序算法性能的关键。常用的有一下几种方式:

1.三数取中

对左端、右端和中间的三个值进行排序,选取中值作为基准关键字。

 

2.取随机数

取一个随机数 m(left <=m<= right),以array[m]作为基准关键字。

 

需要注意快速排序和归并排序的联系和区别:

联系:它们都是基于分治思想的,分组排序。递归实现。

区别:归并排序,是不断的折半分,然后在合并在辅助数组中排序。

    快速排序,根据基准值进行分组,分完之后,基准值的位置就是排序后的位置。

posted @ 2017-03-28 15:26  ren_zhg1992  阅读(204)  评论(0)    收藏  举报