[关闭]
@quinn 2015-03-18T09:56:30.000000Z 字数 1769 阅读 2768

快速排序(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) 的数组进行划分,这一改进成为三者取中法

  1. /*=================三者取其中 快速排序 (需要最后使用插入排序)=======================*/
  2. void quick_sort_middle(Item a[], int l, int r)
  3. {
  4. if(r-l <= M) //小于M的文件不排序,最后统一用插入排序
  5. return;
  6. exch(&a[r-1], &a[(l+r)/2]);
  7. //三交换法对这3个元素排序
  8. comp_exch(&a[l], &a[r-1]);
  9. comp_exch(&a[l], &a[r]);
  10. comp_exch(&a[r-1], &a[r]);
  11. int i = partation(a, l+1, r-1);//a[l]<a[r-1], a[r]>a[r-1]
  12. quick_sort_middle(a, l, i-1);
  13. quick_sort_middle(a, i+1, r);
  14. }

3. 重复关键字

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

  1. /*==========三路法快速排序--可适用于重复关键字(需要最后使用插入排序)=========*/
  2. void quick_sort_3_way(Item a[], int l, int r)//划分操作已经包含在此函数中
  3. {
  4. if(r-l <= M)
  5. return;
  6. int i, j, p, q;
  7. i = l-1, j = r;
  8. p = l, q = r;
  9. Item v = a[r];
  10. for(;;)
  11. {
  12. while(less(a[++i], v));
  13. while(less(v, a[--j]))
  14. if(j == l)
  15. break;
  16. if(j <= i)
  17. break;
  18. exch(&a[i], &a[j]);
  19. //交换和划分元素相等的元素到左右两边
  20. if(a[i] == v)
  21. exch(&a[i], &a[p++]);
  22. if(a[j] == v)
  23. exch(&a[j], &a[q--]);
  24. }
  25. exch(&a[i], &a[r]);
  26. //将相等元素交换到文件中间
  27. i = i-1, j = i+1;
  28. for(int k = l; k < p; k++, i--)
  29. exch(&a[k], &a[i]);
  30. for(int k = r; k > q; k--, j++)
  31. exch(&a[k], &a[j]);
  32. //递归处理子文件
  33. quick_sort_3_way(a, l, i);//此时i所处的位置如图1所示
  34. quick_sort_3_way(a, j, r);
  35. }

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

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

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注