快速排序

本文介绍了快速排序算法的基本原理及其在不同实现方式下的性能差异。通过对比原始实现与原地排序法,展示了如何优化快速排序算法以减少内存使用并提高排序效率。

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

Quick sort是效率不错的一种排序算法,效率上和插入排序、冒泡排序的关系是: >(优于)
快速排序 > 插入排序 > 冒泡排序。
快速排序里面已经有了分治的策略,实现快速排序的核心就是拆分任务、递归。
一个子任务就是:任取数组中的一个数值,将所有的小于该值的数据放到该值的左侧,所有大于等于该值的数据放到该值的右边。
在实现的时候我觉得只需要前半句就行:将所有的小于该值的数据放到该值的左侧。因为这样右侧的一定是后半句。
在开始我实现了一个很锉的快速排序,因为我同时考虑前后半句。我能想到的最直接的办法就是直接重新new两个同样大小的数组,
逐个比较数组中的数据和基准点数据,小于则放到smaller数组里,大于则放到bigger数组里,然后再拷贝回原数组。
测试的结果是正确的,在10000大小的数组中,效率落后于插入排序,甚至不如冒泡排序,所花时间是插入排序的2倍。

代码如下:

template<class T>
static int Partition(int size, T * list)
{
    int pivot = 0;
    T pivotValue = list[pivot];

    int smallerIndex = 0;
    int biggerIndex = 0;

    T *biggers = new T[size];
    T *smallers = new T[size];
    memset((void*)biggers, 0, sizeof(T)*size);
    memset((void*)smallers, 0, sizeof(T)*size);

    smallerIndex = 0;
    biggerIndex = 0;
    for (int i = 1; i<size; ++i)
    {
        if (list[i] > pivotValue)
        {
            biggers[biggerIndex] = list[i];
            ++biggerIndex;
        }
        else
        {
            smallers[smallerIndex] = list[i];
            ++smallerIndex;
        }
    }

    smallers[smallerIndex] = pivotValue;
    ++smallerIndex;

    memcpy((void*)list, (void*)smallers, sizeof(T)*(smallerIndex));

    T * pDest = list + smallerIndex;
    memcpy((void*)pDest, (void*)biggers, sizeof(T)*(size - smallerIndex));

    delete[] smallers;
    delete[] biggers;
    biggers = NULL;
    smallers = NULL;

    return smallerIndex;
}

template<class T>
static void QuickSort(T *list, int size)
{
    if (size <= 1)
        return;

    int smallerSize = Partition(size, list);

    QuickSort(list, smallerSize);
    QuickSort(list + smallerSize, size - smallerSize);
}

static void QuickSortTest()
{
    const int size = SortDefaultSize;
    int list[size] = { 0 };
    FillRandomValue(list, SortDefaultSize);

    //int list[8] = {34, 12, 0, 77, 63, 13, 16, 23};
    PrintArray(list, size);

    Performance *pPerformance = new Performance("QuickSort");
    QuickSort(list, size);
    delete pPerformance;

    PrintArray(list, size);
}

后来仔细的阅读了维基百科上的快排,发现有一种原地快速排序,就如我所说的只需要关注前半句,实现了前半句,后半句自然实现了。

而却原地排序所需要的辅助内存要远远小于每次new的内存,上面的排序时间都花在分配和释放内存了。下面的是一个效率不错的快排:

template<class T>
static size_t Partition(T *list, size_t size)
{
    size_t pivot = 0;
    T pivotValue = list[pivot];
    Swap(list[pivot], list[size - 1]);

    int index = 0;
    for (size_t i = 0; i < size; ++i)
    {
        if (list[i] < pivotValue)
        {
            Swap(list[index], list[i]);
            ++index;
        }
    }

    Swap(list[size - 1], list[index]);

    return index;
}

template<class T>
static void QuickSortInPlace(T *list, size_t size)
{
    if (size <= 1) return;

    size_t pivot = Partition(list, size);

    QuickSortInPlace(list, pivot);
    QuickSortInPlace(list + pivot + 1, size - pivot - 1);
}

static void QuickSortInPlaceTest()
{
    const int size = SortDefaultSize;
    int list[size] = { 0 };
    FillRandomValue(list, size);
    PrintArray(list, size);

    Performance *pPerformance = new Performance("QuickSort-InPlace");
    QuickSortInPlace(list, size);
    delete pPerformance;

    PrintArray(list, size);
}


参考文章:

维基百科-快速排序

http://www.cnblogs.com/butyoux/archive/2013/01/16/2863152.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值