【问题标题】:Quicksort Divide and Conquer快速排序分而治之
【发布时间】:2018-02-09 18:46:29
【问题描述】:

我正在尝试使用 分而治之的技术来实现 Quicksort。我在递归调用中遇到堆栈溢出错误。这是我的代码:

public static void main(String[] args) {
    ArrayList<Integer> unsorted = new ArrayList<Integer>();

    unsorted.add(23);
    unsorted.add(5);
    unsorted.add(1);
    unsorted.add(-8);
    unsorted.add(101);
    unsorted.add(21);
    unsorted.add(10);
    unsorted.add(10);
    unsorted.add(0);
    unsorted.add(50);

    ArrayList<Integer> sorted = Quicksort(unsorted);
    System.out.println(sorted.toString());
}

public static ArrayList<Integer> Quicksort(ArrayList<Integer> unsorted) {

    if (unsorted.size() <= 1)
        return unsorted;

    ArrayList<Integer> less = new ArrayList<Integer>();
    ArrayList<Integer> more = new ArrayList<Integer>();

    int pivotindex = unsorted.size()/2;

    for (int i = 0; i < unsorted.size(); i++) {
        if (unsorted.get(i) < unsorted.get(pivotindex))
            less.add(unsorted.get(i));
        else
            more.add(unsorted.get(i));
    }

    ArrayList<Integer> sorted = Quicksort(less);
    sorted.add(unsorted.get(pivotindex));
    sorted.addAll(Quicksort(more));

    return sorted;
}

我希望它使用ArrayLists 来实现。谁能指出我错在哪里?

非常感谢。

【问题讨论】:

  • 事实上,任何等于枢轴的值(包括枢轴本身)都会添加到more 列表中。
  • 错误似乎在于您在每次运行该方法时都添加了pivotindex 的副本。当你遍历 unsorted 时,没有检查值是否等于 pivotindex,因此它被添加到 more 数组列表中。然后你在sorted.add(unsorted.get(pivotindex)) 再次添加它,这样数组就会永远增长,这会导致你的 stackoverflow 错误。
  • 在 for 循环中,您将枢轴索引处的元素与其自身进行比较,并最终将其作为更少或更多部分添加到排序列表中,并作为枢轴索引处的元素。因此,在每次递归调用时,您都在增加列表的大小,并且调用永远不会结束
  • using ArrayList 如果这是CodeReview,我会指出您仍然应该针对接口而不是类进行编程:声明unsortedlessmoreList&lt;Comparable&gt; (甚至Collection&lt;&gt;,如果您不坚持从中间进行枢轴 - 这提醒我:使用局部变量作为枢轴,而不是它的索引)。使用对Collections 的大小进行合理估计的构造函数。

标签: java algorithm sorting quicksort


【解决方案1】:

您应该将您的pivot 值保存在与moreless 列表不同的位置。

将条件改为:

else if(unsorted.get(i) > unsorted.get(pivotindex))
        more.add(unsorted.get(i));    

它应该可以正常工作。希望这会有所帮助。

编辑:正如 Josh 在评论中提到的,如果有多个元素具有与枢轴相同的值,这将不起作用。为此,您可以定义另一个名为 equal 的 ArrayList 并添加以下行:

else
    equal.add(unsorted.get(i));

然后在合并数组时将此列表与 pivot 元素一起附加。

感谢您指出这一点。 :)

注意:这种排序不能保证稳定(因为具有相同值的元素可能不会根据它们的相对位置放置原始数组中的位置)。

【讨论】:

  • 如果有多个元素与枢轴元素具有相同的值,这仍然有效吗...?使用此方法会丢失这些元素,因为您没有将它们添加到排序列表中。请参阅下面的答案,我将它们保留在其中,并将它们添加到排序列表中。
  • 我想对于这个问题,聪明的解决方案是定义另一个名为 equal 的数组列表,然后在连接数组时将它与枢轴一起放置。
【解决方案2】:

这似乎是一个容易理解的解决方案

ArrayList<Integer> less = new ArrayList<Integer>();
ArrayList<Integer> equal = new ArrayList<Integer>();
ArrayList<Integer> more = new ArrayList<Integer>();

int pivotindex = unsorted.size()/2;

for (int i = 0; i < unsorted.size(); i++) {
    if (unsorted.get(i) < unsorted.get(pivotindex)) //Put whatever is less to the left
        less.add(unsorted.get(i));
    else if (unsorted.get(i) == unsorted.get(pivotindex)) //Put whatever is equal in the middle
        equal.add(unsorted.get(i));
    else //Put everything else to the right (everything greater)
        more.add(unsorted.get(i));
}

ArrayList<Integer> sorted = Quicksort(less); //Sort the left, then add
sorted.addAll(equal); //Middle is already sorted (all equal), add
sorted.addAll(Quicksort(more)); //Sort the right, then add

return sorted;

【讨论】:

    【解决方案3】:

    以下工作完美。

    public static void main(String[] args) {
             ArrayList<Integer> unsorted = new ArrayList<Integer>();
    
                unsorted.add(23);
                unsorted.add(5);
                unsorted.add(1);
                unsorted.add(-8);
                unsorted.add(101);
                unsorted.add(21);
                unsorted.add(10);
                unsorted.add(10);
                unsorted.add(0);
                unsorted.add(50);
    
                ArrayList<Integer> sorted = Quicksort(unsorted);
                System.out.println(sorted.toString());
            }
    
            public static ArrayList<Integer> Quicksort(ArrayList<Integer> unsorted) {
                    System.out.println(unsorted.size());
                if (unsorted.size() <= 1)
                    return unsorted;
    
                ArrayList<Integer> less = new ArrayList<Integer>();
                ArrayList<Integer> more = new ArrayList<Integer>();
    
                int pivotindex = unsorted.size()/2;
    
                for (int i = 0; i < unsorted.size(); i++) {
                    if (unsorted.get(i) < unsorted.get(pivotindex))
                        less.add(unsorted.get(i));
                    else
                        more.add(unsorted.get(i));
                }
                if(less.isEmpty()) {
                    less.add(more.remove(more.size() - 1));
                }
    
                ArrayList<Integer> sorted = Quicksort(less);
                //sorted.add(unsorted.get(pivotindex));
                sorted.addAll(Quicksort(more));
    
                return sorted;
            }
    

    【讨论】:

      猜你喜欢
      • 2015-04-08
      • 2017-05-12
      • 2012-03-04
      • 1970-01-01
      • 2020-07-23
      • 1970-01-01
      • 1970-01-01
      • 2013-11-09
      • 2014-10-13
      相关资源
      最近更新 更多