【问题标题】:SelectionSort variation not workingSelectionSort 变体不起作用
【发布时间】:2014-11-11 09:02:02
【问题描述】:

我必须根据这些参数在 Java 中实现选择排序:

对 SelectionSort 实施一种变体,在扫描列表时定位最小和最大元素,并将它们分别定位在列表的开头和结尾。在第一次通过时,元素 x0,...,xn-1 被扫描;在第二遍中,元素 x1,...,xn-2 被扫描;等等。

我向方法传递了一个大小为 32 的数组,当我打印该数组时,它没有排序。我的代码有什么问题?

static void selectionSort() {
    scramble();
    int smallIndex = 0;  //index of smallest to test
    int largeIndex = array.length - 1;  //index of largest to test
    int small = 0;  //smallest
    int large;  //largest
    int smallLimit = 0;  //starts from here
    int largeLimit = array.length - 1;  //ends here
    int store;  //temp stored here
    int store2;

    for(int i = 0; i < array.length/2; i++) {  //TODO not working...
        small = array[smallLimit];
        large = array[largeLimit];
        for(int j = smallLimit; j <= largeLimit; j++) {
            if(array[j] < small) {
                smallIndex = j;
                small = array[j];
            }
            else if(array[j] > large) {
                largeIndex = j;
                large = array[j];
            }
        }
        store = array[smallLimit];
        store2 = array[smallIndex];
        array[smallLimit] = store2;
        array[smallIndex] = store;
        store = array[largeLimit];
        array[largeLimit] = array[largeIndex];
        array[largeIndex] = store;
        smallLimit++;
        largeLimit--;
    }
    print();    
}

【问题讨论】:

  • 参见 J.B. Hayfron-Acquah、Obed Appiah K. Riverson:“改进的选择排序算法”以获取参考(以及改进的 O(n) 空间选择排序)。重复“Selection sort modified”,或多或少。

标签: java arrays sorting selection-sort


【解决方案1】:

想想极端情况:当在smallLimitlargeLimit 找到最大或最小的项目时会发生什么。发生这种情况时,您会遇到两个问题:

  1. largeIndexsmallIndex 未设置。它们保持之前迭代的值。
  2. 将最小的项目交换到正确的位置会移动最大的项目。第二次交换将最小的项目移动到最大的位置,最大的最终在随机位置。如果您觉得这很难可视化,请在纸上或调试器中逐步执行代码。

这些问题很容易解决。遵循一些准则,您可以避免该问题:

  • 使用更少的活动部件。您始终可以使用smallIndex 获取small 的值,如果您只使用smallIndex,则不会有不同变量失步的危险。
  • 在尽可能小的范围内声明变量。如果smallIndex 在循环体中声明,而不是在编译器之外,编译器会告诉你它有可能在交换之前没有设置。
  • 破坏性更新(例如此处的第一次交换)总是会使之前的计算过时。当您无法避免这种情况发生时,请寻找两个更新可以互相影响的方法。

【讨论】:

    【解决方案2】:

    就像@Joni 一样,明确指出,在遍历数组期间交换两个元素两次 有很大的警告。由于您必须就地实现排序算法,因此您需要考虑要交换的元素的位置,因为它是连续发生的。

    您需要看到的另一个限制情况是只剩下三个元素,即for 循环的最后一次迭代。我会这样做:

        store = array[smallLimit];
        store2 = array[smallIndex];
        array[smallLimit] = small;
        array[smallIndex] = store;
        smallLimit++;
        //No problem with swapping the first two elements
        store = array[largeLimit];
    
        //However the first swap might cause the other elements to shift
        //So we do this check
        if((array[largeIndex] == large))
         {array[largeLimit] = array[largeIndex];
          array[largeIndex] = store;
          largeLimit--;
         }
    
        //Just a limiting case, where amongst the last three elements, first swap happens. 
        //The smallest element is in place, just take care of the other two elements.
        if(largeLimit - smallLimit == 1){
            if(array[largeLimit] != large){
                array[smallLimit] = array[largeLimit];
                array[largeLimit] = large;
                largeLimit--;
            }
        }
    

    为上述 sn-p 工作 DEMO,以您的代码为基础。希望它能让你朝着正确的方向开始。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-05
      • 2022-11-21
      • 1970-01-01
      • 2020-01-28
      • 1970-01-01
      • 1970-01-01
      • 2022-11-10
      • 1970-01-01
      相关资源
      最近更新 更多