【数据结构】大量数据(20万)的快速排序的递归与非递归算法、三数取中思想

原创 2016年05月30日 17:19:28

快速排序的挖坑法与prev、cur法,我们在上一篇博客的第6个排序中讲的非常详细,http://10740184.blog.51cto.com/10730184/1774508【数据结构】常用排序算法(包括:选择排序,堆排序,冒泡排序,选择排序,快速排序,归并排序)    

有兴趣的话,相信聪明的你,一看就会秒懂快速排序的思想。


下面,我们将快速排序优化:

1、三数取中来优化快速排序


优化原因:


快速排序的擦差不多每次将序列一分为二,时间复杂度是O(n*lgn).

wKiom1c-ku6jIeVzAAAhXifwo6A279.png

我们思考,快速排序的时间复杂度是O(n*lgn),在序列乱序时,它的效率很高。但是,当序列有序或者接近有序时,效率就没有那么高了。

如果一个序列是这样的:

{10,5,1,4,5,9,6,1}    

我们针对上述序列,如果要排成升序的话,我们要找一个数满足挖坑法里面的挪数据条件,或者说prev、cur法中的交换数据条件时,可能一直将序列从头遍历,找到结束或者快要结束才找到或者还没有找到,这时候相当于效率就变成了o(n^2)了。


优化方法:

因此,我们想到了三数取中的思想。即序列的三个位置最左边left,最右边right,中间mid,三个数取出中间大小的数,用这个数做key.


三数取中的代码如下:


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



2.非递归的实现


优化原因:

当一个序列较小时,每次将序列再成两半,递归处理两半的序列。

但是,当要给20万、30万这样的序列排序时,每次递归的话,无疑每次调用函数建立栈帧会很很大的系统开销,甚至会耗尽系统的空间。


优化方法:用栈stack模拟实现栈帧,每次压栈出栈---》即递归写法。


递归代码如下:


int PartSort(int* a, int left, int right)
{
    assert(a);
    int cur = left;
    int prev = cur - 1;
    int key = mid(a,left,right);
    swap(key, a[right]);

    while (cur < right)
    {
        if (a[cur] <= a[right])
        {
            swap(a[++prev], a[cur]);
        }
        cur++;
    }
    swap(a[++prev], a[right]);
    
    return prev;
}


void QuickSort(int* a, int left, int right)
{
    int prev = PartSort(a,left, right);

    if (prev - 1 > left)
    {
        QuickSort(a, left, prev - 1);
    }

    if (prev + 1 < right)
    {
        QuickSort(a, prev + 1, right);
    }

}



非递归代码如下(推荐):


//prev、cur法,也可以采用挖坑法等其他办法
int PartSort(int* a, int left, int right)
{
    assert(a);
    int cur = left;
    int prev = cur - 1;
    int key = mid(a,left,right);
    swap(key, a[right]);//将三数取中得到的数据与a[right]处交换。

    while (cur < right)
    {
        if (a[cur] <= a[right])
        {
            swap(a[++prev], a[cur]);
        }
        cur++;
    }
    swap(a[++prev], a[right]);
    
    return prev;
}


void QuickSort_NonR(int* a, int left, int right)
{
    stack<int> s;
    //左右区间压入栈中,或者此时也可以定义一个结构体,里面有左右区间,一次把左右区间都压进去
    s.push(left);
    s.push(right);
    while (!s.empty())
    {
        //[left,right]
        int curRight = s.top();//压栈先压的是左区间,先进后出,取数据先取右区间
        s.pop();
        int curLeft = s.top();
        s.pop();
        int prev = PartSort(a, curLeft, curRight);//将这个区间进行一次快速排序
        if (prev - 1 > curLeft)
        {
            s.push(curLeft);//压入新分的左端序列
            s.push(prev - 1);
        }
        if (prev + 1 < curRight)
        {
            s.push(prev + 1);//压入新分的右段区间
            s.push(curRight);
        }
    }
}


本文出自 “Han Jing's Blog” 博客,请务必保留此出处http://10740184.blog.51cto.com/10730184/1775357

冒泡排序、快速排序(递归&非递归)、堆排序算法比较浅析

最近算法老师让大家抓紧时间完成算法作业,总共四个题目。这几个题目都很不错,我计划着把这四个作业写成四篇博客,一是可以记录下来供大家分享学习,二是可以提升自己对于这几个算法的理解。 任务要求...

快速排序的递归实现算法。

输入:先输入进行排序元素的个数,然后依次随机输入(或随机生成)每个数字。 输出:元素排序后的结果。 示例:输入:8 9 1 2 4 8 6 15 8,输出:1 2 4 6 ...

快速排序的优化--三数取中法

//*********************三数取中法(快排的优化)**************************** //未优化|我们总是把数组尾元素固定为key的值,然后通过调整让key...
  • asd7486
  • asd7486
  • 2016年07月03日 21:00
  • 1318

“三数取中“划分

7-3 “三数取中“划分       有一种改进RANDOM-QUICKSORT的方法,就是根据从子数组更仔细地选择的(而不是随机选择的)元素作为主元来划分。常用的做法是三数 取中:从子数组中随机...

快速排序(三数取中法)源码

快速排序是一种最坏情况时间复杂度为Θ(n2)。虽然最坏情况时间复杂度很差,但是快速排序通常是实际排序应用中最好的选择,因为它的平均性能非常好:它的期望时间复杂度是Θ(nlgn),而且Θ(nlgn)中隐...

基础算法(2):快速排序(随机划分+三数取中划分+ 随机三数取中划分+尾递归)

快速排序:                  简介:快速排序是一种排序算法,包含n个数的输入数组,最坏情况为O(n^2),但是平均性能非常好:期望运行时间为O(n*lg(n))。           ...

DPDK 内存管理(三)(rte_malloc 内存管理)

rte_malloc()为程序运行过程中分配内存,模拟从堆中动态分配内存空间。 1 void * 2 rte_malloc(const char *type, size_t size, unsign...

【OVS2.5.0源码分析】sFlow实现分析(1)

sFlow实现可以分成4个部分:1)配置;2)流表生成(生成datapath的流表);3)datapath中的处理(已经分析);4)sFlow处理过程。本篇分析sFlow的配置过程。 1、bridg...

【数据结构】二叉树(前、中、后)序遍历的递归与非递归算法

对于二叉树,有前序、中序以及后序三种遍历方法。因为树的定义本身就是递归定义,因此采用递归的方法去实现树的三种遍历不仅容易理解而且代码很简洁。而对 于树的遍历若采用非递归的方法,就要采用栈去模拟实现。在...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【数据结构】大量数据(20万)的快速排序的递归与非递归算法、三数取中思想
举报原因:
原因补充:

(最多只允许输入30个字)