快速排序被公认为是本世纪最重要的算法之一,这已经不是什么新闻了。对很多语言来说是实际系统排序,包括在Java中的Arrays.sort

那么快速排序有什么新进展呢?

好吧,就像我刚才提到的那样(Java 7发布两年后)快速排序实现的Arrays.sort双基准(dual-pivot)排序的一种变体取代了。这篇文章不仅展示了为什么这个变化如此优秀,而且让我们看到Jon Bentley和Joshua Bloch的谦逊。

我当时做了什么?

与所有人一样,我想实现这个算法并且对一千万个数值排序(随机数据和重复数据)。奇怪的是,我得到了下面的结果:

随机数据:

  • 基本排序:1222ms。
  • 三路(Three-way)快速排序:1295ms(我是认真的!)。
  • 双基准快速排序:1066ms。

重复数据:

  • 基本排序:378ms。
  • 三路快速排序:15ms。
  • 双基准快速排序:6ms。

愚蠢的问题1

我担心自己在实现三路快速排序的时候遗漏了什么。在多次执行随机输入一千万个数值后,可以看到单点排序始终运行更良好。尽管在执行一千万个数值的时候差距小于100ms。

我现在明白了,用三路快速排序作为默认排序工具的目的。因为在重复数值时,它的时间复杂度没有0(n2)。当我在输入重复值数据时,结果非常明显。但是真的为了处理重复数据的缘故,三路快速排序会受到性能损失吗?或者是我实现方式有问题?

愚蠢的问题2

我的双基准快速排序在实现重复数据的时候并没有处理好,它执行时耗费了0(n2)的时间复杂度。有什么好的办法可以避免吗?实现数组排序时我发现,在实际排序前升序序列和重复就已经能得到很好地消除。所以,作为一种应急的办法,如果定位的数字与比较的数字相等,则增长lowerIndex 去比较下一位数直到与pivot2不相等为止。这种实现会没有问题吗?

1
2
3
4
5
6
else if (pivot1==pivot2){
       while (pivot1==pivot2 && lowIndex<highIndex){
           lowIndex++;
           pivot1=input[lowIndex];
       }
   }

这就是所有内容吗?我究竟做了哪些?

我一直觉得算法跟踪很有趣,但是双基准快速排序中出现的变量个数让我眼花缭乱。所以,接下来我在(三种)实现中都加入了调试信息,这样就可以看出实际运行中不同。

这些可跟踪的类只负责追踪数组下方的指针。希望你能发现这些类是很有用的。

例如一个双基准迭代器:

你可以从哪里下载代码?

整个项目(连同一些蹩脚的DSA实现)的实现可以在GitHub上找到。快速排序类就可以在这里找到。

这是我的实现单基准(Hoare),三路快排(Sedgewick)和新双基准(Yaroslavskiy)。

单基准:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package basics.sorting.quick;
import static basics.sorting.utils.SortUtils.exchange;
import static basics.sorting.utils.SortUtils.less;
import basics.shuffle.KnuthShuffle;
public class QuickSortBasic {
  public void sort (int[] input){
      //KnuthShuffle.shuffle(input);
      sort (input, 0, input.length-1);
  }
  private void sort(int[] input, int lowIndex, int highIndex) {
      if (highIndex<=lowIndex){
          return;
      }
      int partIndex=partition (input, lowIndex, highIndex);
      sort (input, lowIndex, partIndex-1);
      sort (input, partIndex+1, highIndex);
  }
  private int partition(int[] input, int lowIndex, int highIndex) {
      int i=lowIndex;
      int pivotIndex=lowIndex;
      int j=highIndex+1;
      while (true){
          while (less(input[++i], input[pivotIndex])){
              if (i==highIndex) break;
          }
          while (less (input[pivotIndex], input[--j])){
              if (j==lowIndex) break;
          }
          if (i>=j) break;
          exchange(input, i, j);
      }
      exchange(input, pivotIndex, j);
      return j;
  }
}

三基准

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package basics.sorting.quick;
import static basics.shuffle.KnuthShuffle.shuffle;
import static basics.sorting.utils.SortUtils.exchange;
import static basics.sorting.utils.SortUtils.less;
public class QuickSort3Way {
  public void sort (int[] input){
      //input=shuffle(input);
      sort (input, 0, input.length-1);
  }
  public void sort(int[] input, int lowIndex, int highIndex) {
      if (highIndex<=lowIndex) return;
      int lt=lowIndex;
      int gt=highIndex;
      int i=lowIndex+1;
      int pivotIndex=lowIndex;
      int pivotValue=input[pivotIndex];
      while (i<=gt){
          if (less(input[i],pivotValue)){
              exchange(input, i++, lt++);
          }
          else if (less (pivotValue, input[i])){
              exchange(input, i, gt--);
          }
          else{
              i++;
          }
      }
      sort (input, lowIndex, lt-1);
      sort (input, gt+1, highIndex);
  }
}

双基准

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package basics.sorting.quick;
import static basics.shuffle.KnuthShuffle.shuffle;
import static basics.sorting.utils.SortUtils.exchange;
import static basics.sorting.utils.SortUtils.less;
public class QuickSortDualPivot {
  public void sort (int[] input){
      //input=shuffle(input);
      sort (input, 0, input.length-1);
  }
  private void sort(int[] input, int lowIndex, int highIndex) {
      if (highIndex<=lowIndex) return;
      int pivot1=input[lowIndex];
      int pivot2=input[highIndex];
      if (pivot1>pivot2){
          exchange(input, lowIndex, highIndex);
          pivot1=input[lowIndex];
          pivot2=input[highIndex];
          //sort(input, lowIndex, highIndex);
      }
      else if (pivot1==pivot2){
          while (pivot1==pivot2 && lowIndex<highIndex){
              lowIndex++;
              pivot1=input[lowIndex];
          }
      }
      int i=lowIndex+1;
      int lt=lowIndex+1;
      int gt=highIndex-1;
      while (i<=gt){
          if (less(input[i], pivot1)){
              exchange(input, i++, lt++);
          }
          else if (less(pivot2, input[i])){
              exchange(input, i, gt--);
          }
          else{
              i++;
          }
      }
      exchange(input, lowIndex, --lt);
      exchange(input, highIndex, ++gt);
      sort(input, lowIndex, lt-1);
      sort (input, lt+1, gt-1);
      sort(input, gt+1, highIndex);
  }
}

http://www.importnew.com/8445.html

快速排序—三路快排 vs 双基准相关推荐

  1. 快速排序 详解(快速排序 双路快排 三路快排)

    注:内容,图片来自于慕课网liuyubobobo老师的课程.  官方代码链接:https://github.com/liuyubobobo/Play-with-Algorithms 快速排序 快速排序 ...

  2. 归并排序、快速排序、二路快排、三路快排python实现

    源代码: https://github.com/lzneu/Algrithm_python O(n*logn)级别的排序: |-归并排序     分成log(n)个层级 每个层级进行O(n)排序   ...

  3. 三路快排算法加强版(三路快排的再次改进)

    :不要忘记初心哈 :) 理论依据 快排算法的缺陷及其逐一改进 三路快排尽可能三等份划分区间 通过待排元素的区间长度划分? 通过待排元素的最值之差划分? 直接使用待排元素的最大值划分? 实验数据 大范围 ...

  4. LeetCode 75. Sort Colors (python一次遍历,模拟三路快排)

    LeetCode 75. Sort Colors (python一次遍历,模拟三路快排) 题目分析: 本题需要实现数字只包含0,1,2的排序,并且要求一次遍历. 由于只用把数字隔离开,很容易想到快排的 ...

  5. java三路快排,java二路快排很慢

    老师,以下是我二路快排的java代码 public class quickSortTwoway { public quickSortTwoway() {}; public static void qu ...

  6. LeetCode--75.颜色分类(三路快排,计数排序)

    颜色分类(C) 1. 题目描述 2. 题目解析 3. C语言实现 3.1 三路快排法 3.2 计数排序法 1. 题目描述 难度:中等 2. 题目解析 这道题需要注意一下几点: 原地进行排序,不可以另外 ...

  7. 快速排序、快排的优化 及Java实现

    一.快速排序的思想 选取一个比较的基准,将待排序数据分为独立的两个部分,左侧都是小于或等于基准,右侧都是大于或等于基准,然后分别对左侧部分和右侧部分重复前面的过程,也就是左侧部分又选择一个基准,又分为 ...

  8. 使用Java泛型实现快速排序(快排,Quicksort)

    原文:https://my.oschina.net/u/1382972/blog/169747 还可以参考:http://blog.csdn.net/stushan/article/details/5 ...

  9. 八大排序算法之快速排序(下篇)(快排的优化+非递归快排的实现)

    目录 一.前言 1.快速排序的实现: 快速排序的单趟排序(排升序)(快慢指针法实现):​ 2.未经优化的快排的缺陷 二.快速排序的优化 1.三数取中优化 优化思路: 2. 小区间插入排序优化 小区间插 ...

最新文章

  1. controller接收json数据_答疑 | 前后端分离,如何接收json数据?
  2. 一口气说出 6 种 @Transactional 注解的失效场景
  3. C1之路 | 训练任务03-WEB
  4. Response笔记
  5. wince6.0中文内核定制
  6. mysql 改成宽松模式_mysql5.6 sql_mode设置为宽松模式
  7. 存档:命令行程序的路径参数不能有空格
  8. ajax在php中使用方法,在项目中如何使用ajax请求
  9. 汇编三星题目:一个有符号字数组以0为结束标志,编程求这个数组的最大值、 最小值、平均值
  10. Unity-拓展篇-接入海康威视摄像头
  11. 解决笔记本电脑有线耳机插入无反应的情况
  12. Foxmail中配置Gmail实现gmail客户端收(转)
  13. 第一篇自用博客:git的操作(防忘记用的hh)封面是我最爱的歌手ikura强推她的每一首歌,简直就是行走的唱片啊有木有!
  14. 零基础学平面设计要从哪入手
  15. java程序员语录_java程序员励志说说26条
  16. 2022,这些大屏可视化素材,够你用一整年了(附可视化素材包)
  17. 懂23种语言 2019年上市 宝马的AI助理有哪些不同!
  18. Warning: Leaking Caffe2 thread-pool after fork
  19. 阅读文献:VOLO: Vision Outlooker for Visual Recognition
  20. virtualization - Ubuntu Budgie screen distortion in Hyper-V - Ask Ubuntu

热门文章

  1. Java学习之JDBC(1)
  2. 关于ASP.NET给产品分类,分页,详情页生成静态页面
  3. windows下如何使用QT编写dll程序 .
  4. 微软面试题之两个链表的第一个公共结点
  5. givemesomecredit数据_EasyEnsemble:一种简单的不平衡数据的建模方法(附测试代码)...
  6. who I am ?
  7. 计算机网络作业第六章,计算机网络与通信第6章习题.doc
  8. python对象_Python对象()
  9. junit5 动态测试_JUnit 5嵌套测试
  10. 中心管理cms服务器_如何查找网站使用的CMS,脚本,服务器,技术