八种排序算法(一)------快速排序

本文详细介绍了快速排序算法的基本思想,包括基准值的选择、分区过程及递归实现,并探讨了算法优化方法如三数取中法,同时给出了非递归实现方式。此外,还分析了快速排序的时间复杂度和稳定性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

算法思想

找一个基准值,本题中基准值为数组中最右的元素,再定义两个指针begin(指向首元素)、end(指向尾元素);

begin从前往后走找比基准值大的元素,找到后停下;end从后往前走找比基准值小的元素,找到后也停下;然后,交换arry[begin]和arry[end],依次循环操作;

当begin与end相遇,将arry[begin]或arry[end]与基准值交换

代码实现(递归):

#include <stdio.h>

int PartSort(int* a,int right,int left)
{
    int key = a[right];
    int keyid = key;
    while(right > left)
    {
        while(right > left || a[left] <= key)
            ++left;
        while(left < right || a[right] >= key)
            --right;
        if(a[left] != a[right])
            Qswap(&a[left],&a[right]);
    }
    Qswap(&a[left],&a[keyid]);
    return left;
}

//递归实现
void QuickSort(int *a,int left,int right)
{
    if(a == NULL || right < 0 || left < 0)
        return 0;
    if(left < right)
    {
        int div = PartSort(a,left,right);

        QuickSort(a,left,div-1);
        QuickSort(a,div+1,right);
    }

}

算法优化

三数取中法

选择这组数据的第一个元素、中间元素、最后一个元素,这三个元素里面值居中的元素作为基准数;

代码实现:

#include<stdio.h>
int Max(int a,int b)
{
    return a>b?a:b;
}
int Min(int a,int b)
{
    return a>b?b:a;
}

int GetMidIndex(int* a,int left,int right)
{
    if(a == NULL || left<0 || right < 0)
        return 0;
    int mid = left + (right - left)>>1;
    int max1 = Max(a[left],a[right]);
    int max2 = Max(a[mid],Min(a[left],a[right]));
    int MidIndex = Min(max1,max2);

    return MidIndex;

    
}

非递归实现:

#include<stdio.h>
#include<stack>
using namespace std;

class Sort
{
    public:
    void Quick_sort(int *arr,int len)
    {
        std::stack<int> Stack;
        if(arr == NULL || len < 0)
            return ;
        int left = 0;
        int right = len - 1;
        int pivot = 0;
    
        Stack.push(left);
        Stack.push(right);
        
        while(!Stack.empty())
        {
            int begin = Stack.top();
            Stack.pop();
            int end = Stack.top();
            Stack.pop();
            
            pivot = PartSort(arr,begin,end);
            if(begin<pivot-1)
            {
                Stack.push(pivot-1);
                Stack.push(left);
            }
            if(pivot + 1 < end)
            {
                Stack.push(end);
                Stack.push(pivot+1);
            }

        }
    }
};

复杂度分析

快速排序的时间代价很大程度上取决于枢轴的选择,最简单的办法就是选择第一个记录或者最后一个记录作为枢轴值,但这样做的弊端在于当原始的输入序列已经有序,每次分割会将剩余的记录全部分到一个序列当中,而另外一个序列为空。这种情况也是最差的情况(eg:第一趟经过n-1次比较,第一个记录定在原始位置,左半子序列为空,右半子序列为n-1个记录;第二趟n-1个经过n-2次比较,第2个记录定在原始位置,左半子序列仍为空,右半子序列为n-2个记录,以此类推,共需进行n-1趟排序,其比较次数为[(n-1)+(n-2)+......+(n-(n-1))]=n(n-1)/2=O(n^2)【时间复杂度取最高项,然后忽略掉其系数】;

最好的情况就是,每次分割都恰好将记录序列分为两个长度相等的子1序列。初始的n个记录序列,第一次分割为两个长度为n/2的子序列,第2次分割为4个长度为n/4的子序列,以此类推,总共需要分割logn次,所有分割步数之和为n,因此最终的时间复杂度为O(nlogn).

稳定性

因为快速排序每次移动记录的跨度比较大,因此快排是不稳定的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值