快排详解

本文详细介绍了快速排序的三种方法:最早的方法、挖坑法和前后指针法,并提供了对应的代码实现。此外,还讨论了快排的两种实现方式:递归和循环,并分析了快排的时间复杂度。最后,提出了两种优化方案:三数取中法和直接插入法。

一、快排的三种方法

1、最早的方法
(1)思路:给出一个key值(默认为数组第一个位置上的数),从数组开头开始找大于key的数,数组末端开始找小于key的数,找到之后两位置上的数进行交换
(2)画图理解:
这里写图片描述
(3)代码:

int Partition2(int*arr, int left, int right)
{
    itn start=left;
    int key = arr[left];
    while (left < right)
    {
        while (left < right&&arr[left] <= key)
            left++;
        while (left<right&&arr[right]>=key)
            right--;
        if (left < right)
            swap(arr[left], arr[right]);
    }
    //特例如{5,6},key为5,不判断就交换,数组就无序了
    if (arr[left]<key)//注意点,要记得判断一下
        swap(arr[left], arr[start]);
    return left;
}

2、挖坑法
(1)思路:给出一个key值(默认为数组第一个位置上的数),在该位置上挖一个坑。这个位置上就少了一个数;然后从数组右边开始遍历,寻找一个值比key小的数,挖出这个数来,对上一个坑进行填坑。然后从数组前面遍历,寻找一个比key大的数,填上面的坑。直到左边和右边相遇,最后把key补在坑上
(2)画图理解:这里写图片描述
(3)代码:

int Partition(int*arr, int start, int end)
{
    int key = arr[start];
    while (start < end)
    {
        while (start < end&&key <= arr[end])//注意要写上=
            end--;
        if (start < end)
            arr[start]= arr[end];
        while (start < end&&key >= arr[start])
            start++;
        if (start < end)
            arr[end] = arr[start];
    }
    arr[start] = key;
    return start;
}

3、前后指针法
(1)思路:设置前后指针,前指针依次++,后指针只有在前指针指向的数小于key的时候++。当后指针++,并且其++后的值不等于前指针,那么俩位置上的数交换。当快指针到到最后位置,把key的值交换到前指针的后一个位置上。
(2)画图理解:
这里写图片描述
(3)代码:


int Partion(int*arr,int start, int end)
{
        int key = arr[end];
    int ps = start - 1;
    int pf = start;
    while (pf < end)
    {
        if (arr[pf] < key&&(++ps != pf))
            swap(arr[pf], arr[ps]);
        ++pf;
    }
    swap(arr[end], arr[++ps]);
    return ps;
}

二、快排两种实现方式

1、递归

void Qsort(int*arr, int start, int end)
{
    if (start < end)
    {
        int index = Partition3(arr, start, end);
        Qsort(arr, start, index - 1);
        Qsort(arr, index + 1, end);
    }
}

2、循环

void Qsort1(int*arr, int start, int end)
{
    stack<int>coll;
    coll.push(end);
    coll.push(start);
    while (!coll.empty())
    {
        int left = coll.top();
        coll.pop();
        int right = coll.top();
        coll.pop();
        int index = Partition3(arr, left, right);
        if (left < index - 1)
        {
            coll.push(index - 1);
            coll.push(left);
        }
        if (index + 1 < right)
        {
            coll.push(right);
            coll.push(index + 1);
        }
    }
}

三、快排的时间复杂度

这里写图片描述
快排最优的情景:就是如上图所示key的值取到中间值,递归次数最少
快排最差的情景:就是key值取到了边界值(最大或最小),递归的次数为n,时间复杂度为O(N)

四、对快排的优化

1、三数取中法:对于key取值位置的优化,有可能key取到边界值,造成快排的效率变低。具体实现是,判断前中后三个点的值,取中间的值作为key。


int midpos(int*arr, int left, int right)
{
    int mid = left + (right - left) / 2;
    if (arr[left] > arr[right])
    {
        if (arr[mid] > arr[left])
            return left;
        else if (arr[mid] < arr[right])
            return right;
        else
            return mid;
    }
    else
    {
        if (arr[mid]>arr[right])
            return right;
        else if (arr[mid] < arr[left])
            return left;
        else
            return mid;
    }
    return -1;
}

2、如果对一段长度小于13的数据进行排序,可用直接插入法替代快排,可以有效减少递归深度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值