排序算法O(n^2)系列之选择排序

74 阅读1分钟

这是我参与更文挑战的第16天,活动详情查看: 更文挑战

选择排序

相对于冒泡排序,选择排序多一个变量,专门存储最小值、最大值的下标,等每轮次循环遍历结束后,才会进行两个元素的交换。这样比冒泡排序减少了交换次数。

SEL.gif

1. 基本实现

public static void main(String[] args) {
    int[] arr = new int[]{189, -6, 0, 1, 34, 78};
    selectionSort(arr);
    Arrays.stream(arr).forEach(System.out::println);
}

public static void selectionSort(int[] arr) {
    int count = 0, length = arr.length, minIndex;
    for (int i = 0; i < length - 1; i++) {
        minIndex = i;
        for (int j = i + 1; j < length; j++) {
            if (arr[minIndex] > arr[j]) {
                minIndex = j;
            }
            count++;
        }
        int temp = arr[i];
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
    }
    System.out.println("循环进行了 " + count + " 次");
}

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

//output
循环进行了 15 次
-6
0
1
34
78
189

Process finished with exit code 0

2. 优化版本1

既然每轮遍历时找出了最小值,同时把最大值也顺便找出来。这就是二元选择排序的思想。

使用二元选择排序,每轮选择时记录最小值和最大值,可以把数组需要遍历的范围缩小一倍。


public static void main(String[] args) {
    int[] arr = new int[]{189, -6, 0, 1, 34, 78};
    selectionSort(arr);
    Arrays.stream(arr).forEach(System.out::println);
}

public static void selectionSort(int[] arr) {
    int minIndex, maxIndex,count=0;
    for (int i = 0; i < arr.length / 2; i++) {
        minIndex = i;
        maxIndex = i;
        for (int j = i + 1; j < arr.length - i; j++) {
            if (arr[minIndex] > arr[j]) {
                minIndex = j;
            }
            if (arr[maxIndex] < arr[j]) {
                maxIndex = j;
            }
            count++;
        }
        if (minIndex == maxIndex) break;
        int temp = arr[i];
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
        if (maxIndex == i) maxIndex = minIndex;
        int lastIndex = arr.length - 1 - i;
        temp = arr[lastIndex];
        arr[lastIndex] = arr[maxIndex];
        arr[maxIndex] = temp;
    }
    System.out.println("循环进行了 " + count + " 次");
}

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

//output
循环进行了 9 次
-6
0
1
34
78
189

Process finished with exit code 0

总结

从代码可以看出,虽然二元选择排序最外层的遍历范围缩小了,但 for 循环内做的事情翻了一倍。也就是说二元选择排序无法将选择排序的效率提升一倍。但实测会发现二元选择排序的速度确实比选择排序的速度快一点点。

声明:此文中的图引自网络。