【问题标题】:Quicksort java with median of first 3 elements前3个元素中位数的快速排序java
【发布时间】:2016-04-06 04:25:57
【问题描述】:

我无法使用快速排序。我的家庭作业要求我将枢轴设为前 3 个元素的中位数,或者如果列表小于 3,则设为第一个元素。当我这样做时,排序会分崩离析,并且某些元素会被其他元素覆盖。我不确定我错过了什么,但这里是代码:

private static <E extends Comparable<E>> int partition(ArrayList<E> list, int first, int last) {
    ArrayList<E> subList = new ArrayList<E>(list.subList(first, last));
    E pivot = list.get(0);

    int low = first + 1; // Index for forward search
    int high = last; // Index for backward search

    if(list.get(0).getClass().equals(String.class)){
        while (high > low) {
            // Search forward from left
            while (low <= high && list.get(low).toString().compareToIgnoreCase(pivot.toString()) <= 0)
                low++;

            // Search backward from right
            while (low <= high && list.get(high).toString().compareToIgnoreCase(pivot.toString()) > 0)
                high--;

            // Swap two elements in the list
            if (high > low) {
                E temp = list.get(high);
                list.set(high, list.get(low));
                list.set(low, temp);
            }
        }

        while (high > first && list.get(high).toString().compareToIgnoreCase(pivot.toString()) >= 0)
            high--;

        // Swap pivot with list.get(high)
        if (pivot.toString().compareToIgnoreCase(list.get(high).toString()) > 0) {
            list.set(first, list.get(high));
            list.set(high, pivot);
            return high;
        }
        else {
            return first;
        }
    }else{
        //same code, but doesn't convert toString for comparisons
    }
} 

当我替换第 3 行时,问题就出现了。

//E pivot = list.get(0);
//change to
E pivot = getPivot(subList);

这里是get pivot的代码:

private static <E extends Comparable<E>> E getPivot(ArrayList<E> list){
    if(list.size() < 3){
        return list.get(0);
    }else{
        //sorts ignoring case if the type of data in the list is strings
        if(list.get(0).getClass().equals(String.class)){
            if(list.get(0).toString().compareToIgnoreCase(list.get(1).toString()) > 0){
                if(list.get(0).toString().compareToIgnoreCase(list.get(2).toString()) <= 0){
                    return list.get(0);
                }else if(list.get(1).toString().compareToIgnoreCase(list.get(2).toString()) > 0){
                    return list.get(1);
                }
            }else if(list.get(0).toString().compareToIgnoreCase(list.get(1).toString()) <= 0){
                if(list.get(0).toString().compareToIgnoreCase(list.get(2).toString()) > 0){
                    return list.get(0);
                }else if(list.get(1).toString().compareToIgnoreCase(list.get(2).toString()) <= 0){
                    return list.get(1);
                }
            }
        }else{
            //same code, but doesn't convert toString for comparisons
        }
    }
    return list.get(2);
}

我不确定从这里去哪里,我让它工作的唯一方法是如果 getPivot 方法每次都返回第一个元素,但它没有任何作用。有人可以指出我正确的方向吗?谢谢。

【问题讨论】:

  • 你有没有单独测试过这个方法? getPivot 方法是否始终返回正确答案?如果是,那不是问题,如果不是,在什么情况下会失败?
  • 我确实单独测试了该方法,并且在所有情况下都可以正常工作。

标签: java quicksort median


【解决方案1】:

就在您返回之前,当交换以将枢轴置于列表中间时,您错误地假设枢轴始终位于第一个位置。因此,您可能会丢失位于列表第一个位置的值,而会获得枢轴值的副本。您需要记住在哪个索引处找到了枢轴,并使用该索引而不是第一个索引进行交换。

还有另一个问题。当您将low 变量初始化为first + 1 时,您还假设枢轴位于第一个位置。您不应该在此处添加 1。否则,您最终可能会得到一个大于第一个位置的枢轴的值。

【讨论】:

  • 这帮助很大,我现在没有重复的问题,但是我的一些接近开始的元素仍然不合适。一个由 9, 7, 5, 11, 12, 2, 14, 3, 10, 6 组成的数组列表按 3, 5, 2, 6, 7, 9, 10, 11, 12, 14 排序。怀疑它与while循环中的起始位置有关,我会测试一下。
  • @Hephaestus 假设您运行了一次分区迭代,这是正确的。快速排序实现的典型分区步骤仅对数组进行排序,使得所有大于枢轴的元素都位于枢轴的右侧,而所有小于枢轴的元素都位于枢轴的左侧。见wikipedia quicksort article。它不保证分区本身是排序的。要对数组进行完全排序,您需要在生成的两个分区上递归地应用分区步骤。
  • 我已经在递归调用它,我只需要更改条件检查以交换枢轴并将值从 > 返回到 >=,并在之前的 while 循环中从 >= 进行比较只是>。我检测了每一行代码以找出问题所在。
猜你喜欢
  • 1970-01-01
  • 2018-03-16
  • 1970-01-01
  • 1970-01-01
  • 2014-05-18
  • 2020-06-21
  • 1970-01-01
  • 2020-04-30
  • 1970-01-01
相关资源
最近更新 更多