快速排序 递归与非递归

绪论: 由于平常用c++STL里面的sort习惯了,所以很少用过快速排序,同时也对快速排序有一种恐惧感,一直以为自己不会写,但是仔细想想快排的思想,还是很容易理解的,

只要思维达到一个高度,就都不是问题了。

交换排序:说到快排,就要先说到交换排序,因为快排是交换排序的一种,而说的交换排序,就不得不先说最简单的冒泡排序。因为任何高明的算法都不是一下子就能想出来的,都是在已有的基础上进行不断的优化得来的。

冒泡排序:冒泡排序的过程就是首先将第一个关键字与第二个关键字进行比较,如果是逆序的(a[1] > a[2]),从1开始n结束,则进行交换,第一趟排序(交换)是从1到n,结果最大的在第n个位置上,然后接下来第i趟排序都要把最大的交换到n-i+1的位置上,最终经过n-1趟排序,时间复杂度为O(n2)。

优化:现在再来想想改进算法了,如果我们可以想到分割的思想(很多算法都用到),每次交换和比较只要比较一部分,比如分为两半,这样的话比较和交换的代价就会小很多,所以我们就想到每一趟排序都把待排记录分为独立的两部分,其中一部分的关键字比另一部分的关键字小,这样只要分别对这两部分精心进行排序就可以使整体有序。

于是就有了快速排序,但是其代码实现不尽相同,效率也有不同。比如说递归和非递归,递归里关于枢轴的设置。有人可能以为递归就够了,但是有一些公司面试或机试时专门让写一个非递归的快排,这时如果不理解其中的思想就跪了。下面只是对快排几种写法的简单的探索。


递归写法

递归主体函数:


void  quicksort(int *a, int low, int high)
{
    if (low < high)
    {
        int p = Partition1(a, low, high);//p就是分为两半后中间的那个关键字
        quicksort1(a, low, p-1);
        quicksort1(a, p+1, high);
    }
}

再有就是关于Partition函数的实现了,可以说是快排算法里核心内容,实现方法不同,效率也不同


int Partition1(int *a, int low, int high)
{
    int x = a[low];
    int pivotkey = a[low];
    while(low < high)
    {
        while (low < high && a[high] >= pivotkey) high--;
        a[low] = a[high];
        while (low < high && a[low] <= pivotkey) low++;
        a[high] = a[low];
    }
    a[low] = x;
    return low;
}

int Partition2(int *a, int low, int high)
{
    int x = a[high];
    int i = low-1;
    for (int j = low; j < high; j++)
    {
        if (a[j] < x)
        {
            i++;
            int t;
            t = a[j];
            a[j] = a[i];
            a[i] = t;
        }
    }
    int t = a[i+1];
    a[i+1] = a[high];
    a[high] = t;
    return i+1;
}


我学习到的目前有这两种:

第一种是数据严蔚敏数据结构课本里的,大致思路是设一个数为枢轴,并通过从两头向中间遍历,使枢轴放到一个确定的位置,使左边的都小于枢轴上的关键字,右边的都大于枢轴上的关键字。

第二种是从算法导论里边的,思路是从最做到右遍历一遍,找到小于枢轴的就交换到左边。

对于这两种方法的效率比较我用了一组数据进行了测试,数据为大小为 0xffffff的随机数并把其保存的文件里,首先声明,关于时间都只是一个相对的概念,毕竟我的电脑配置不高。

经过比较第一种算法比第二种效率高,可能第一种是从两边进行比较的缘故,而且交换不像第二种每次交换都是t = a, a = b, b = t 的过程,而只是一步。

所以之后的算法我只测试Partition1,然后又把Partition1这个函数放到了quicksort函数里面进行了测试。


非递归写法:

非递归写法其实就是手动建立一个栈的过程,所以算法关键是这个栈的优劣,下面是两种写法:用STL里的栈和用数组表示栈。


void no_recursion_quicksort_stl(int *a, int low, int high)
{
    stack<int> Stack;
    Stack.push(low);
    Stack.push(high);
    while (!Stack.empty())
    {
        int r = Stack.top();
        Stack.pop();
        int l = Stack.top();
        Stack.pop();
        int p = Partition1(a, l, r);
        if (p-1 > l)
        {
            Stack.push(l);
            Stack.push(p-1);
        }
        if (p+1 < r)
        {
            Stack.push(p+1);
            Stack.push(r);
        }
    }
}


int Stack[100000];
void no_recursion_quicksort_array(int *a, int low, int high)
{

    int top = 0;
    Stack[top++] = low;
    Stack[top++] = high;
    while (top != 0)
    {
        int r = Stack[--top];
        int l = Stack[--top];
        int p = Partition1(a, l, r);
        if (p-1 > l)
        {
            Stack[top++] = l;
            Stack[top++] = p-1;
        }
        if (p+1 < r)
        {
            Stack[top++] = p+1;
            Stack[top++] = r;
        }
    }
}

结果是非递归写法中用STL的栈比递归写法效率更低,而用数组表示栈效率并没有提高。可能是我的算法有问题,先留下问题等待以后研究。











  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值