快速排序(2)算法改进--小的子文件、三者取中、重复关键字三路划分

标签(空格分隔): 排序算法


1. 小的子文件

由于快速排序会递归的调用自身的许多小文件,因而要对小的子文件尽可能使用高效的算法
直观来想即,if(r-l <= M) insertion(a, l, r);,M为子文件规模的阈值。

而一种更高效的实现方式是,在快速排序过程中直接忽略小的子文件,
if(r-l <= M) return;
在快速排序完成后,再进行一次整个数组的插入排序。即使子文件的阈值设置较大,因为只有极少数的文件进行了划分操作,所以快速排序部分运行很快;而插入排序操作的对象是几乎有序的文件,所以插入排序部分运行也很快。这个忽略小文件技术无论何时都适用于递归算法,因为本质在于,我们确信所有递归算法在执行小问题实例时会占据时间的大部分。因而可以采用一些混合算法改进总的运行时间。

具体程序上的改进,参见三者取其中的程序实现

2. 三者取其中划分

对快速排序的另一项改进,即使用一个尽可能在文件中间划分的划分元素(避免最坏情况):对此有2种办法,一种是采用数组中的一个随机元素,但是在实际应用中不可能使用随机数生成器;
简单的随意选择可能也是高效的,因此可得到我们另一种划分元素的方法:

从文件中取出三个元素,使用三个元素的中间元素作为划分元素。取数组的最左右两边的元素a[l] a[r]和中间位置的元素a[(l+r)/2],对这三个数排序,用a[r-1]和a[(l+r)/2]交换,然后对(l+1, r-1) 的数组进行划分,这一改进成为三者取中法

/*=================三者取其中 快速排序 (需要最后使用插入排序)=======================*/
void quick_sort_middle(Item a[], int l, int r)
{
    if(r-l <= M)    //小于M的文件不排序,最后统一用插入排序
        return;

    exch(&a[r-1], &a[(l+r)/2]);
    //三交换法对这3个元素排序
    comp_exch(&a[l], &a[r-1]);
    comp_exch(&a[l], &a[r]);
    comp_exch(&a[r-1], &a[r]);

    int i = partation(a, l+1, r-1);//a[l]<a[r-1], a[r]>a[r-1]
    quick_sort_middle(a, l, i-1);
    quick_sort_middle(a, i+1, r);
}

3. 重复关键字

带有大量重复关键字值使用基本的快速排序性能会极其低效。
直观想是将文件分为3部分:
此处输入图片的描述
三路划分法:将标准的划分作如下改动,扫描时将遇到左子文件中和划分元素相等的元素放在文件的最左边,遇到右子文件中和划分元素相等的元素放在文件的最右边。最后在将左右相等的关键字交换到中间,此时,这些元素都已经在最终位置,从递归调用中去除它们。
此处输入图片的描述

/*==========三路法快速排序--可适用于重复关键字(需要最后使用插入排序)=========*/
void quick_sort_3_way(Item a[], int l, int r)//划分操作已经包含在此函数中
{
    if(r-l <= M)
        return;
    int i, j, p, q;
    i = l-1, j = r;
    p = l, q = r;
    Item v = a[r];
    for(;;)
    {
        while(less(a[++i], v));
        while(less(v, a[--j]))
            if(j == l)
                break;
        if(j <= i)
            break;
        exch(&a[i], &a[j]);
        //交换和划分元素相等的元素到左右两边
        if(a[i] == v)
            exch(&a[i], &a[p++]);
        if(a[j] == v)
            exch(&a[j], &a[q--]);
    }
    exch(&a[i], &a[r]);
    //将相等元素交换到文件中间
    i = i-1, j = i+1;
    for(int k = l; k < p; k++, i--)
        exch(&a[k], &a[i]);
    for(int k = r; k > q; k--, j++)
        exch(&a[k], &a[j]);
    //递归处理子文件
    quick_sort_3_way(a, l, i);//此时i所处的位置如图1所示
    quick_sort_3_way(a, j, r);
}

4. 上述三个部分完整程序

http://download.csdn.net/detail/quzhongxin/8512515
http://pan.baidu.com/s/1o6l2qN4
参考资料:《算法:C语言实现》P201

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值