排序算法之快速排序

快速排序由C. A. R. Hoare在1962年提出。排序效率在同为O(N*logN)的排序算法中算是很高的。
它的基本思想是:

1.先从序列中选取一个数作为基准数
2.所有比基准数小的,放在基准数的左边,所有比基准数大的放在基准数的右边。
3.将基准数左右两边的序列,分别执行上述两个步骤,直至数列有序。

它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod)。

假设有这样一个序列:
array[8] = {49,38,65,97,76,13,27,49};

01234567
4938659776132749

假设我为选取第left = 0个元素 49作为我们第一次分组的基准数 pivot = 49,此处0位置处有一个”坑”。

01234567
38659776132749

当左边出现”坑”时,从右边的下标位置,即位置right = 7起开始”填坑”,填坑的原则是 “小而赋值(填坑),大而移动”,即,,比基准值大的,向左移动,比基准值小的,放到坑里去。
经过分析下标为right = 7的数据为49与基准值pivot相等,继续左移right –,下标right = 6的数据为27,比基准值小,要完成赋值 。此时right = 6的位置是一个坑。

01234567
27386597761349

当右边出现”坑”时,从左边的下标位置,即位置left = 0起开始”填坑”,填坑的原则是,”大而赋值(填坑),小而移动”,即,比基准值小的,向右移动,比基准值大的,放到坑里面去。
经过分析下标为left = 0的数据为27与基准值pivot小,右移一位left++,下标为left = 1的数据为38,比基准值小,继续右移left++,下标为left = 2的数据为65比基准值要大,要完成赋值 。此时left = 2的位置是一个坑。

01234567
27389776136549

当左边出现”坑”时,从右边的下标位置,即位置right = 6(即上一次被填坑的位置)起开始”填坑”,原则同上,right = 6的值为65比基准值要大,左移right–,right=5的值为13比基准值要小,完成赋值。此时right = 5处的位置是一个坑。

01234567
27381397766549

当右边出现”坑”时,从左边的下标位置,即位置left = 2(即上一次被填坑的位置)起开始”填坑”,原则同上,right = 2的值为13比基准值要小,右移left++,left=3的值为97比基准值要大,完成赋值。此时left = 3处的位置是一个坑。

01234567
27381376976549

当左边出现”坑”时,从右边的下标位置,即位置right = 5(即上一次被填坑的位置)起开始”填坑”,原则同上,right = 6的值为65比基准值要大,左移right–,right=4的值为76比基准值要大,继续左移right–,此时left = right = 3,将基准值入到left = right相等处的坑中。

01234567
2738134976976549

此时即完成了,第一轮分组。 左侧值 小于 pivot; 右侧值 大于等于 pivot

依据上述规则,分别对pivot左右两侧的序列执行上述操作,直至有序。

这里写图片描述

此时我们要完成代码的编写,再次对原则进行归纳:

1.先从序列中选取一个数作为基准数
2.所有比基准数小的,放在基准数的左边,所有比基准数大的放在基准数的右边。
3.将基准数左右两边的序列,分别执行上述两个步骤,直至数列有序。

为 :
1.左右填坑,直到找到pivot所在的坑,并完成赋值。
2.依据pivot所在的位置进行分组,重复上述步骤。

完成步骤1的代码如下:

int findPivotPostion(int *arr, int left, int right)
{
    int pivot = arr[left];
    while(left < right)
    {
        while(left<right && arr[right] >= pivot) // 大而(>=)移动,
            right--;
        arr[left]  =  arr[right]; //小而赋值

        while(left<right && arr[left]  <=  pivot) //小而(<=)移动
            left++;
        arr[right]  =  arr[left]; //大而赋值

    }
    arr[left] = pivot;  // 为基准值找到位置
    return left;
}

完成步骤2的代码如下:

void quickSort(int *arr, int left ,int right)
{
    if(left < right)
    {
        int pos = findPivotPostion(arr,left, right);
        quickSort(arr,left,pos-1);
        quickSort(arr,pos+1,right);
    }
}

为了更简名之,合并之:

void quickSort(int *arr, int left ,int right)
{
    if(left < right)
    {
        int pivot = arr[left];
        int low = left; int high = right;
        while(left < right)
        {
            while(low<high && arr[hig] >= pivot) // 大而(>=)移动,
                high--;
            arr[low]  =  arr[high]; //小而赋值

            while(low<high && arr[low]  <=  pivot) //小而(<=)移动
                low++;
            arr[high]  =  arr[low]; //大而赋值

        }
        arr[low] = pivot;  // 为基准值找到位置

        quickSort(arr,left,low-1);
        quickSort(arr,low+1,right);
    }
}

测试代码如下:

int main()
{
    int array[8] = {49,38,65,97,76,13,27,49};

    for(int i=0; i<8; i++)
        printf("%5d",array[i]);
    putchar(10);
    quickSort(array,0,7);
    for(int i=0; i<8; i++)
        printf("%5d",array[i]);

    return 0;
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

developer_wgl

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值