【数据结构】大量数据(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

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

关于递归和循环

一. 递归的慢究竟慢在哪 递归就是函数自己调用自己,函数每次调用的时候需要将以下内容存入递归栈:调用函数地址、形参、局部变量、返回值。所以如果递归调用了N次,那压栈操作要保存N * 调用函数地址、N...
  • zdp072
  • zdp072
  • 2015-04-15 09:18
  • 1046

大数据递归思维

在初学计算机编程时,我想大多数人的经历会和作者一样,学校为我们挑选一门语言,大多为 C 或 Java,先是基本的数据类型,然后是程序控制语句,条件判断,循环等,书上会教我们如何定义一个函数,会说程序就...

数据结构----二叉树遍历的非递归算法实现

#include   #include   #include      #define OK 0;   #define ERROR -1   #define OVERFLOW -2 ...
  • hegq1
  • hegq1
  • 2012-11-28 22:43
  • 321

【数据结构】二叉树四种遍历的非递归算法

递归算法虽然简洁,但一般而言,其执行效率不高。因此,有时候要把递归算法转化为非递归算法。先序遍历非递归算法由先序遍历过程可知,先访问根节点,再访问左子树,最后访问右子树。因此,先将根节点进栈,在栈不空...

数据结构例程——二叉树遍历的非递归算法

本文是数据结构基础系列(6):树和二叉树中第11课时二叉树遍历非递归算法的例程。【二叉树遍历的非递归算法】 实现二叉树的先序、中序、后序遍历的非递归算法,并对用”A(B(D,E(H(J,K(L,M(...

c(数据结构)下树的创建的非递归算法

#include #include #include #define M 100//定义最大的节点数 //创建二叉树的类型 typedef struct TNode{     char d...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

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