选择排序增长有序范围从两端

时间:2012-04-17 11:13:09

标签: java sorting duplicates selection-sort

我已经编写了一个选择排序的修改版本,我将其视为数组的最小值和最大值,并将它们放在两端

算法就像这样

1. Find the minimum and the maximum value in the list.
2. Swap the minimum value with the value in the first position.
3. Swap the maximum value with the value in the last position.
4. Repeat the steps above for the remainder of the list 
(starting at the second position and ending at the second to 
 last position and narrowing the range of positions examined 
 from both ends of the array each time).

不幸的是,上面显示了具有重复值的数组的意外结果。

例如,

[9, 37, 12, 1, 13, 31, 5, 37, 36, 29, 19, 22, 20, 15, -1, 23]

分类到

[-1, 1, 5, 9, 12, 13, 15, 19, 20, 22, 23, 29, 31, 37, 36, 37]

实际上,这里的主要问题是算法一般不对数组后半部分的元素进行适当的排序,除了简单的重复之外。

这是我的伪代码

    int i=0;
    while(i<=(arr.length-i-1)) {
      int minIndex = i;
      int maxIndex=arr.length-i-1; 
      for (int j = i+1; j <=arr.length-i-1; j++) {

       if (arr[j] <=arr[minIndex]) {
         minIndex = j;      
         } 
       if(arr[j]>=arr[maxIndex]){
          maxIndex = j; 
         }
      }
      swap(arr, i, minIndex);
      swap(arr, (arr.length-i-1), maxIndex); 
    i++;
    }

编辑这是我的代码的交换部分,它是与算法交互的唯一内容。我不认为这会有任何不同,但无论如何我都会把它包括在内

 private static void swap(int[] arr, int oldIndex, int newIndex){

    int temp=arr[oldIndex];
    arr[oldIndex]=arr[newIndex];
    arr[newIndex]=temp;
 }

5 个答案:

答案 0 :(得分:3)

i恰好是maxIndex时会出现问题。要解决此问题,您需要添加:

swap(arr, i, minIndex);
if(i == maxIndex) {
     maxIndex = minIndex;
}
swap(arr, (arr.length-i-1), maxIndex);

See it @work

答案 1 :(得分:2)

好的,问题是最大值从迭代的最小位置开始。考虑在问题数组上第二次循环:

-1,37,12,1,13,31,5,23,36,29,19,22,20,15,9,37

i为1,len-i-1为14.循环后,maxindex为1,minIndex为3。

所以你交换1(i)和3(minIndex):

-1,1,12,37,13,31,5,23,36,29,19,22,20,15,9,37

然后是14(len-i-1)和1(maxIndex):

-1,9,12,37,13,31,5,23,36,29,19,22,20,15,1,37

糟糕。基本上,您需要并行进行两次交换。

编辑并行性在两次重叠交换的情况下不会真正有用,因为每个交换都希望在其中一个数组插槽中放入不同的值;你必须解决冲突。我认为@ codaddict的解决方案效果很好。

答案 2 :(得分:0)

内部for循环的终止条件中有一个off-by-one错误。

  for (int j = i+1; j <=arr.length-i-1; j++) {

应该是<,而不是<=,原因与您使用i+1而不是i的原因相同。

作为一种风格推荐,我还会将值arr.length - i - 1存储在一个变量中,因为它在代码中显示了四次。

编辑:已验证此错误不是问题的根源。

答案 3 :(得分:0)

我认为你做了太多交换 - 即无论你是否真的找到新的最小值或最大值,你都在进行交换。此外,你不需要做两个测试(min和max,因为你不能两者兼而有之,除非在平凡的平凡情况下,在这种情况下,它们在哪个顺序并不重要......)。

我认为以下是您算法的更好表示:

int arrayLength = arr.length;
for (int i=0; i<arrayLength; i++){
  for (int j=i+1; j<arrayLength; j++){
    int v = arr[j];
    if (v < arr[i]){
      swap(arr, i, j);
    } else if (v > arr[(arrayLength -1)]){
      swap(arr, (arrayLength -i-1), j);
    }
  }
}

但是,您实际上并不需要对最大值进行测试以将它们交换到最后,因为这些都将通过搜索最小值来捕获,因为您通过阵列进行顶级迭代 - 即

int arrayLength = arr.length;
for (int i=0; i<arrayLength; i++){
  for (int j=i+1; j<arrayLength; j++){
    int v = arr[j];
    if (v < arr[i]){
      swap(arr, i, j);
    } 
  }
}

会更有效率。

编辑:在回顾了其他答案之后,这种对Mark Reed关于并行进行掉期交易的回答有所了解 - 除此之外,我建议你按照你的需要进行掉期交易。

答案 4 :(得分:-2)

在评论中,你的第一次交换会很好,但你的第二次交换会产生问题。

如果您的maxindex变量位于i,则您正确地放置了最小术语,但丢失了最长期限。这可以通过添加一个检查if(i==maxterm)的额外条款来解决,并通过第二次正常交换和第二次交换maxterm和minterm位置来处理这种特殊情况。从0到array.length-1

遍历数组是没用的

我建议,从0到(array.length-1)/ 2遍历,因为你在两边排序。最终部分已经按照起始部分排序,为什么要进行额外的迭代?我已经编写了一个完全相同的程序,我建议使用更正,并检查数字是否已经排序并立即终止循环。