为什么此算法无法正确排序最后一个索引?

时间:2018-10-25 17:42:49

标签: java arrays sorting selection-sort

我应该写一个选择排序算法的版本,将最小的数字移到数组的前面,同时将最大的数字移到数组的末尾。我知道它基本上是从两端开始工作的,所以有两个排序的子数组,但是我的代码似乎放错了数组中的最后一个数字。我的代码:

public static void dualSelectionSort(int[]a) {
    for(int i=0; i<a.length-1;i++) {
        int min=i;
        int max=(a.length-1)-i;
        for (int j=i+1;j<a.length-i;j++) {
            if(a[j]<a[min]) {
                min=j;
            }
            if(a[j]>a[max]) {
                max=j;
            }
        }
        int temp1=a[min];
        int temp2=a[max];
        a[min]=a[i];
        a[max]=a[(a.length-1)-i];
        a[i]=temp1;
        a[(a.length-1)-i]=temp2;
    }
}

如果给定输入[5,4,3,2,1],它将输出[1,2,5,3,4]而不是[1,2,3,4,5]。 我想念什么?

2 个答案:

答案 0 :(得分:3)

问题出在内部循环中。

从i + 1开始。 因此,用于比较max的代码实际上是将a [1]与a [4]进行比较。

您可以将其更改为 for (int j=i;j<a.length-i;j++)

正如您可以在注释中阅读的那样,在某些情况下,如果进行上述更改,代码仍将无法工作。 发生这种情况的原因是i == max,因此现有的交换方法将行不通。 例如: 假设数组= [6,4,5],内循环max = 0,min = 1。现有交换将使其变为[4,6,6]。 因此,交换应以不同的方式处理。

      if(i==max) {
            swap(a,max,a.length-1-i);
            swap(a,min,i);
        }else {
            swap(a,min,i);
            swap(a,max,(a.length-1)-i);
        }  

完整的代码如下:

public static void dualSelectionSort(int[]a) {
    for(int i=0; i<a.length-1;i++) {
        int min=i;
        int max=(a.length-1)-i;

        for (int j=i;j<a.length-i;j++) {
            if(a[j]<a[min]) {
                min=j;
            }
            if(a[j]>a[max]) {
                max=j;
            }
        }
        if(i==max) {
            swap(a,max,a.length-1-i);
            swap(a,min,i);
        }else {
            swap(a,min,i);
            swap(a,max,(a.length-1)-i);
        }       
    }
}

public static void swap(int[] a,int i,int j) {
    int temp = a[i];
    a[i] = a[j];
    a[j] = temp;
}

答案 1 :(得分:2)

在外循环的每次迭代中,您都将第一个索引(i)作为初始最小索引,最后一个索引(a.length-1-i)作为初始最大索引。然后,将这两个索引与范围为i + 1到a.length-i-1的所有索引进行比较。但是,如果第一个索引(i)实际上包含最大值,则永远不要将其与a [max]进行比较,因此a [max]在内部循环的末尾永远不会包含正确的值。

这是建议的解决方法:

public static void dualSelectionSort(int[]a) {
    for(int i = 0; i < a.length - i - 1; i++) {
        if (a[i] > a[(a.length - 1) - i]) {
            int temp = a[i];
            a[i] = a[(a.length - 1) - i];
            a[(a.length - 1) - i] = temp;
        }
        int min = i;
        int max = (a.length - 1) - i;
        for (int j = i + 1; j < (a.length -1 ) - i; j++) {
            if(a[j] < a[min]) {
                min = j;
            }
            if(a[j] > a[max]) {
                max = j;
            }
        }
        int temp1 = a[min];
        int temp2 = a[max];
        a[min] = a[i];
        a[max] = a[(a.length - 1) - i];
        a[i] = temp1;
        a[(a.length - 1) - i] = temp2;
    }
}

我改变了三件事:

  1. 外循环可以比结束快得多-i >= a.length-i-1-因为在每次迭代中都会找到最小值和最大值,因此可以将剩余的未排序数组减少2。

  2. 在初始化minmax索引时,请确保min索引实际上包含一个比max索引小的值。如果是a[i] > a[(a.length-1)-i],请先交换它们,然后再将min设置为i,将max设置为(a.length-1)-i

  3. 内部循环应将ji+1迭代到(a.length-1)-i-1