【问题标题】:Quicksort with 3-way partition具有 3 路分区的快速排序
【发布时间】:2019-08-18 23:22:54
【问题描述】:

什么是具有 3 路分区的 QuickSort?

    标签: algorithm quicksort


    【解决方案1】:

    画一个数组:

    3, 5, 2, 7, 6, 4, 2, 8, 8, 9, 0
    

    一个两分区快速排序将选择一个值,例如 4,并将每个大于 4 的元素放在数组的一侧,将每个小于 4 的元素放在另一侧。像这样:

    3, 2, 0, 2, 4, | 8, 7, 8, 9, 6, 5
    

    一个三分区快速排序将选择两个值进行分区并以这种方式拆分数组。让我们选择 4 和 7:

    3, 2, 0, 2, | 4, 6, 5, 7, | 8, 8, 9
    

    这只是常规快速排序的一个微小变化。

    您继续对每个分区进行分区,直到对数组进行排序。 运行时在技术上是 nlog3(n) 与常规快速排序的 nlog 略有不同2(n)。

    【讨论】:

    • 现在有趣的问题是:“在什么情况下,n 路 QS 比 m 路 QS 更好?”
    • 在进行自己的研究时遇到了这篇文章……我不得不说我一半同意这个答案。是的,它被分成 3 个分区,但只有一个枢轴,每个分区是 <,=,>。进行上述分区似乎并没有比标准 2 分区增加任何好处。对于通过谷歌搜索来的人来说,只是我的 2 便士。
    • 编辑:现在进一步阅读实际上是一个双轴分区算法,这是 JDK7 中的当前实现,显然被证明是截至 2012 年最有效的策略。=)grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…
    • 我的意思是有不止一种分区算法。 3 路分区(例如 Bentley-McIlroy)只有 1 个主元,用于处理重复键。我不知道双支点策略,所以我对它进行了研究。 =)所以你的评论帮助了我。
    • 事实上,3 路分区可以是 1 轴或 2 轴 - 请参阅 sorting-algorithms.com/quick-sort-3-way 以前不知道这一点
    【解决方案2】:

    【讨论】:

    • 这似乎是正确的答案。当有许多重复键时,三向快速排序处理性能。
    【解决方案3】:

    如果您真的使用Akra-Bazzi formula 将分区数作为参数进行数学运算,然后对该参数进行优化,您会发现 e ( =2.718...) 分区提供了最快的性能。然而,在实践中,我们的语言结构、cpu 等都针对二进制操作进行了优化,因此标准划分为两组将是最快的。

    【讨论】:

    • 啊!正是我想要的。谢谢。
    • the standard partitioning to two sets will be fastest -需要引用
    【解决方案4】:

    我认为 3 路分区是由 Djstrka 设计的。

    考虑一个包含元素{ 3, 9, 4, 1, 2, 3, 15, 17, 25, 17 } 的数组。

    基本上,您设置了 3 个分区:小于、等于和大于某个枢轴。等于分区不需要进一步排序,因为它的所有元素都已经相等。


    例如,如果我们选择第一个 3 作为枢轴,那么使用 Dijkstra 的 3 路分区将排列原始数组并返回两个索引 m1m2 使得所有索引小于 @987654325 的元素@将低于3,所有索引大于等于m1且小于等于m2的元素将等于3,所有索引大于m2的元素将大于3

    在这种特殊情况下,结果数组可能是{ 1, 2, 3, 3, 9, 4, 15, 17, 25, 17 },而值m1m2 将是m1 = 2m2 = 3

    请注意,结果数组可能会根据用于分区的策略而改变,但数字 m1m2 将是相同的。

    【讨论】:

      【解决方案5】:

      我认为这与 Dijkstra 分区方式有关,其中分区的元素小于、等于和大于枢轴。只有较小和较大的分区必须递归排序。您可以在the walnut 看到一个交互式可视化并使用它。我在那里使用的颜色是红色/白色/蓝色,因为分区方法通常被称为“荷兰国旗问题”

      【讨论】:

        【解决方案6】:

        3 路快速排序基本上将数组划分为 3 个部分。第一部分小于枢轴,第二部分等于枢轴,第三部分大于枢轴。它是线性时间分区算法。 这种划分类似于荷兰国旗问题。

        【讨论】:

          【解决方案7】:
            //code to implement Dijkstra 3-way partitioning
          
            package Sorting;
          
            public class QuickSortUsing3WayPartitioning {
          
          private int[]original;
          private int length;
          private int lt;
          private int gt;
          
          public QuickSortUsing3WayPartitioning(int len){
              length = len;
              //original = new int[length];
          
              original = {0,7,8,1,8,9,3,8,8,8,0,7,8,1,8,9,3,8,8,8};
          
          }
          
          public void swap(int a, int b){ //here indexes are passed
              int temp = original[a];
              original[a] = original[b];
              original[b] = temp;
          }
          
          public int random(int start,int end){
              return (start + (int)(Math.random()*(end-start+1)));
          }
          
          public void partition(int pivot, int start, int end){
              swap(pivot,start);  // swapping pivot and starting element in that subarray
          
              int pivot_value = original[start];
              lt = start;
              gt = end;
          
              int i = start;
              while(i <= gt) {
          
                  if(original[i] < pivot_value) {
                      swap(lt, i);
                      lt++;
                      i++;
                  }
          
                  if(original[i] > pivot_value) {
                      swap(gt, i);
                      gt--;
                  }
                  if(original[i] == pivot_value)
                      i++;
              }
          }
          
          public void Sort(int start, int end){
              if(start < end) {
          
                  int pivot = random(start,end); // choose the index for pivot randomly
                  partition(pivot, start, end); // about index the array is partitioned
          
                  Sort(start, lt-1);
                  Sort(gt+1, end);
          
              }
          }
          
          public void Sort(){
              Sort(0,length-1);
          }
          
          public void disp(){
              for(int i=0; i<length;++i){
                  System.out.print(original[i]+" ");
              }
              System.out.println();
          }
          
          public static void main(String[] args) {
          
              QuickSortUsing3WayPartitioning qs = new QuickSortUsing3WayPartitioning(20);
              qs.disp();
          
              qs.Sort();
              qs.disp();
          
          }
          
          }
          

          【讨论】:

          • 为什么不使用 {} 符号在一行中初始化 original ?现在,它看起来很丑。
          • 请辩解在答案中它如何回答What is QuickSort with a 3-way partition?。这也被称为“荷兰国旗算法”——“双支点”怎么样?
          • @greybeard 这个双支点又名 3 路分区问题是著名的“荷兰国旗算法”的变体
          猜你喜欢
          • 2020-09-04
          • 1970-01-01
          • 2015-10-28
          • 2010-12-06
          • 2018-09-13
          • 2017-05-09
          • 2021-06-11
          相关资源
          最近更新 更多