【问题标题】:Reduce Complexity of Quicksort method降低快速排序方法的复杂性
【发布时间】:2018-10-16 09:32:43
【问题描述】:

大家好,我有一个问题,我正在尝试降低这段代码的复杂性(在底部)。我的想法是删除 while 循环中的 If 子句,但我有点做不到。我在这里尝试做的是比较 SortArray 的两个元素并使用快速排序算法对它们进行排序。目标是使算法尽可能简单。 Smaller 和 Bigger 是遍历数组并在元素大于枢轴时切换的索引。更大的是在中间的末端,可以与枢轴切换。

   if (records.getElementAt(smaller).compareTo(Pivot) > 0 ) {


        swap(records, smaller, bigger);
        bigger--;

        }

我的想法是将 while 循环的条件和 if 子句合二为一,但这对我不起作用。我什至尝试了两个 while 循环,其中一个是

 while (smaller <= bigger && records.getElementAt(smaller).compareTo(Pivot)>0 

和其他的

while (smaller <= bigger && records.getElementAt(smaller).compareTo(Pivot)<0

但这也没有用。

import frame.SortArray;

public class QuickSortA extends QuickSort {

/**
 * Quicksort algorithm implementation to sort a SorrtArray by choosing the
 * pivot as the first (leftmost) element in the list
 * 
 * @param records
 *            - list of elements to be sorted as a SortArray
 * @param left
 *            - the index of the left bound for the algorithm
 * @param right
 *            - the index of the right bound for the algorithm
 * @return Returns the sorted list as SortArray
 */
@Override
public void Quicksort(SortArray records, int left, int right) {
    // TODO
    // implement the Quicksort A algorithm to sort the records
    // (choose the pivot as the first (leftmost) element in the list)
    if (left < right) {
    int a = Partition(records, left, right);
        Quicksort(records, left, a - 1);
        Quicksort(records, a + 1, right);
    }   

}   

public static int Partition(SortArray records, int left, int right) {

    int smaller = left + 1;
    int bigger  = right;
    SortingItem Pivot = records.getElementAt(left);


    while (smaller <= bigger ) {

        if (records.getElementAt(smaller).compareTo(Pivot) > 0 ) {


            swap(records, smaller, bigger);
            bigger--;

            }

        else

            smaller++;                
        }
    swap(records, bigger, left);    
    return bigger;





}

public static void swap(SortArray records, int small, int big) {
    SortingItem Tauschvariable;
    Tauschvariable = records.getElementAt(small);
    records.setElementAt(small, records.getElementAt(big));
    records.setElementAt(big, Tauschvariable);
}

// You may add additional methods here

}

public class SortArray {

private int numberOfItems;

private ArrayList<SortingItem> listOfItems;

private int readingOperations;
private int writingOperations;

/**
 * @param numberOfItems
 *            number of items to hold
 */
public SortArray(ArrayList<String[]> items) {
    numberOfItems = items.size();
    readingOperations = 0;
    writingOperations = 0;
    listOfItems = new ArrayList<>();

    for (String[] element : items) {
        SortingItem s = new SortingItem();
        s.BookSerialNumber = element[0];
        s.ReaderID = element[1];
        s.Status = element[2];
        listOfItems.add(s);
    }
}

【问题讨论】:

  • 你不能让quicksort#partition 效率不高于 O(n) (r - l) ...而且你不能/不应该像这样组合 while 条件:因为原始循环确实某些东西(特别是关于术语。条件),当较小的元素大于枢轴并且当较低(等于)时! ..在您接近时,您运行 2 个(独立的)序列,一个 - 其中较小的元素大于枢轴,另一个 - 不是;)(其中一个可能是无限的!!:)
  • @xerx593 嘿,谢谢您的回答!好的,我明白你的意思,我在过去的 20 分钟里一直在尝试,所以你为我节省了很多时间。您认为还有另一种方法可以降低这里的复杂性吗?任何事情都会有帮助!目前我给出的一项测试失败了,它说:complexity out of allowed range: O(n^2) required!

标签: java while-loop complexity-theory quicksort partition


【解决方案1】:

在正确实现的情况下,快速排序的平均复杂度为 O(NlogN)。问题是最坏情况的复杂度可能是 O(N^2),具体取决于您选择分区的方式。

分区始终将输入子数组拆分为 2 个大小完全不相等的子数组时的最坏情况问题。如果您反复将 N 大小的数组拆分为大小为 1 和 N - 1 的数组,那么您最终会进行 N 次拆分。而且由于每个分区步骤都会比较所有 N 个元素,因此您最终会进行 N * O(N) 次比较;即 O(N^2)。

无论如何,最坏情况问题的解决方案是改变您选择枢轴的方式......以尽量避免输入已经排序(或几乎排序)时的病态行为。而不是选择第一个元素作为枢轴,您可以:

  • 随机选择枢轴
  • 从数组的不同部分挑选三个候选主元,然后选择中间的一个,
  • 等等

作为记录,有一个数学证明表明基于比较的排序算法具有下限 Ω(NlogN)。

参考资料:

【讨论】:

  • 谢谢@Stephen C,你可能是对的,因为现在失败的测试总是正确的,即使其他两个是错误的,所以我猜这个输入已经排序了!这对我很有帮助,谢谢!
  • 我应该选择第一个元素作为枢轴,但这会使事情变得更难。
  • 另一种解释可能是swap 不是 O(1)。例如,如果 SortArray 的 get 和 set 操作不是 O(1)。那可能吗?你自己实现了那个类吗?
  • 我自己实现了交换,但没有实现 SortArray。每次我访问数组时,它都会添加读写操作。 SortArray 看起来像这样
  • 另一种可能的解释是您使用的测试框架没有正确估计代码的复杂性! (询问班上的其他学生是否有这个问题......)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-07
  • 2023-03-06
  • 2021-06-29
  • 2017-11-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多