快速排序

快速排序

思想:

快速排序的思想巧秒,利用分治的思想,可以极快排序数组。其基本思想分两步:
1. 给你一个数组,让你选择数组中的任意一个数作为基数,然后让数组中所有比基数小的数都放在放在基数的左边,所有比基数大的数放在基数的右边。
2. 将刚才基数的位置作为中点,将数组中基数左边的所有元素做1操作,将基数右边的所有元素做1操作。
看到步骤2,就很容易想到这里面是递归调用的。所以我们的关键任务就是如何让第一步高效快速实现。

代码:

先看代码,我们来实现步骤1:


// 选n为基准, 使左边的数都比它下, 右边的数都比它大
// 返回基准在数组中的位置
int insertToMid(int arr[], int left, int right, int n)
{
    int i = left;
    int j = right;
    while (i < j)
    {
        for (; i < j; --j)
        {
            if (arr[j] < n)
            {
                arr[i] = arr[j];
                ++i;
                break;
            }
        }

        for (; i<j; ++i)
        {
            if (arr[i] > n)
            {
                arr[j] = arr[i];
                --j;
                break;
            }
        }
    }
    arr[i] = n;
    return i;
}

解释一下:选取的基数是n,是外部传入的(后面可以看到其实是数组中的第一个元素)。然后让i和j分别指向数组的开头和结尾。从数组的最后开始向前找第一个比n小的数,将这个数与赋值到i位置上(比n小的数放到n的左边)。然后又从i+1位置往后找第一个比n大的数,将这个数赋值到j位置上(比n大的数放到n的右边)。(由于第一路找第一个比n小的数的时候,是总末尾开始找的,所以可以保证现在赋值的位置的右边都是比n大的数。),直到i=j的时候,就是n该放到的中间位置。然后返回i的索引位置。

看看图解:
这里写图片描述

到这里我们完成了步骤1(选取基数,排序后使基数左边的数都小于基数,让基数右边的数都大于基数,当然这里的排序不是严格的从低到高,而是一个范围大小的归类。这样基数右边的所有数都大于基数左边的数了

然后再完成步骤2就简单了,看看代码:

//快速排序
void quickSort(int arr[], int left, int right)
{
    if (left < right)
    {
        int mid = insertToMid(arr, left, right, arr[left]);
        quickSort(arr, left, mid - 1);
        quickSort(arr, mid + 1, right);
    }
}

解释:这里之所以让insertToMid()返回中间值就是为了进行递归调用,将基数左边的所有数执行步骤1,右边的所有数也执行步骤1。到最后只剩两个数的时候就,就一定为有序数列了。

图解:
这里写图片描述

总结:

快速排序的时间复杂度为 O(nlog2(n)),其快慢主要区别就是在步骤1上,当然是先步骤1可以采取自己的方法,只要能达到要求就行了。这种分治的思想还是非常先进的,感觉自己明白的又多了。

提供另外一种将讲数插入中间, 使左边数都比它小, 右边数都比它大的方法, 自己琢磨一下, 代码很简洁

int partion(int A[], int left, int right){
    int point = A[right];
    int index = left;
    for(int i=index; i<=right; ++i){
        if(A[i] <= point){
            swap(A[i], A[index]);
            index++;
        }
    }
    return index-1;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值