2.2 选择排序:简单但有效的交换最小化策略

历史背景

选择排序的历史同样悠久,其基本思想——"每次选择最小元素放到前面"——可以追溯到人类手动排序的原始方法。在计算机科学中,选择排序是最早被形式化描述的排序算法之一。它的优势在于交换次数最少,对于交换成本较高的场景(如大对象的排序)有一定价值。

算法原理

选择排序的基本思想是:将数组分为已排序区间和未排序区间。每一轮从未排序区间中找到最小元素,将其与未排序区间的第一个元素交换位置。这样,已排序区间就扩展了一个元素。重复这个过程,直到所有元素都排序完毕。

Java 实现

java
复制代码
public class SelectionSort {
    
    /**
     * 选择排序
     * @param arr 待排序的整数数组
     */
    public static void sort(int[] arr) {
        int n = arr.length;
        for (int i = 0; i < n - 1; i++) {
            int minIndex = i;
            // 在未排序区间 [i, n-1] 中查找最小元素
            for (int j = i + 1; j < n; j++) {
                if (arr[j] < arr[minIndex]) {
                    minIndex = j;
                }
            }
            // 将最小元素交换到已排序区间的末尾
            if (minIndex != i) {
                int temp = arr[i];
                arr[i] = arr[minIndex];
                arr[minIndex] = temp;
            }
        }
    }
    
    /**
     * 选择排序(泛型版本)
     */
    public static <T extends Comparable<T>> void sortGeneric(T[] arr) {
        int n = arr.length;
        for (int i = 0; i < n - 1; i++) {
            int minIndex = i;
            for (int j = i + 1; j < n; j++) {
                if (arr[j].compareTo(arr[minIndex]) < 0) {
                    minIndex = j;
                }
            }
            if (minIndex != i) {
                T temp = arr[i];
                arr[i] = arr[minIndex];
                arr[minIndex] = temp;
            }
        }
    }
    
    /**
     * 双向选择排序
     * 每轮同时找出最小值和最大值,分别放到两端
     */
    public static void sortBidirectional(int[] arr) {
        int left = 0, right = arr.length - 1;
        while (left < right) {
            int minIndex = left, maxIndex = right;
            for (int i = left; i <= right; i++) {
                if (arr[i] < arr[minIndex]) minIndex = i;
                if (arr[i] > arr[maxIndex]) maxIndex = i;
            }
            // 注意处理边界情况
            int temp = arr[left];
            arr[left] = arr[minIndex];
            arr[minIndex] = temp;
            
            if (maxIndex == left) {
                maxIndex = minIndex;
            }
            
            temp = arr[right];
            arr[right] = arr[maxIndex];
            arr[maxIndex] = temp;
            
            left++;
            right--;
        }
    }
}

效率分析

指标 最好情况 最坏情况 平均情况
时间复杂度 O(n²) O(n²) O(n²)
空间复杂度 O(1) O(1) O(1)
比较次数 n(n-1)/2 n(n-1)/2 n(n-1)/2
交换次数 0 n-1 n-1

选择排序是不稳定的排序算法(例如 [5a, 5b, 3] 排序后 5a5b 的相对顺序可能改变),但是原地排序。它的最大特点是交换次数固定为 n-1 次,是所有基于比较的排序算法中交换次数最少的。

应用场景

  • 数据交换成本远高于比较成本的场景(如大对象数组)
  • 内存写入操作受限的环境(如闪存、EEPROM)
  • 小规模数据排序
  • 教学演示