基础算法学习 | 3.选择排序

118 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第10天,点击查看活动详情

image.png

往期内容

基础算法学习 | 1.二分查找

基础算法学习 | 2.冒泡排序

前言

选择排序是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

算法实现

算法描述

  1. 将数组分为两个子集,排序的和未排序的,每一轮从未排序的子集中选出最小的元素,放入排序子集

  2. 重复以上步骤,直到整个数组有序

算法实现

public static void selection(int[] a) {
    for (int i = 0; i < a.length - 1; i++) {
        // i 代表每轮选择最小元素要交换到的目标索引
        int s = i; // 代表最小元素的索引
        for (int j = s + 1; j < a.length; j++) {
            // j 元素比 s 元素还要小, 更新 s
            if (a[s] > a[j]) {
                s = j;
            }
        }
        if (s != i) {
            int tmp = a[s];
            a[s] = a[i];
            a[i] = tmp;
        }
        System.out.println(Arrays.toString(a));
    }
}

测试代码

public static void main(String[] args) {
    int[] array = {1, 40, 47, 3, 20, 35, 49, 60, 8, 11, 48};
    selection(array);
}

运行结果

[1, 40, 47, 3, 20, 35, 49, 60, 8, 11, 48]
[1, 3, 47, 40, 20, 35, 49, 60, 8, 11, 48]
[1, 3, 8, 40, 20, 35, 49, 60, 47, 11, 48]
[1, 3, 8, 11, 20, 35, 49, 60, 47, 40, 48]
[1, 3, 8, 11, 20, 35, 49, 60, 47, 40, 48]
[1, 3, 8, 11, 20, 35, 49, 60, 47, 40, 48]
[1, 3, 8, 11, 20, 35, 40, 60, 47, 49, 48]
[1, 3, 8, 11, 20, 35, 40, 47, 60, 49, 48]
[1, 3, 8, 11, 20, 35, 40, 47, 48, 49, 60]
[1, 3, 8, 11, 20, 35, 40, 47, 48, 49, 60]
  • 优化点:为减少交换次数,每一轮可以先找最小的索引,在每轮最后再交换元素

与冒泡排序比较

  1. 二者平均时间复杂度都是 O(n2)O(n^2)

  2. 选择排序一般要快于冒泡,因为其交换次数少

  3. 但如果集合有序度高,冒泡优于选择

  4. 冒泡属于稳定排序算法,而选择属于不稳定排序

    • 稳定排序指,按对象中不同字段进行多次排序,不会打乱同值元素的顺序
    • 不稳定排序则反之

稳定排序与不稳定排序

System.out.println("=================不稳定================");
Card[] cards = getStaticCards();
System.out.println(Arrays.toString(cards));
selection(cards, Comparator.comparingInt((Card a) -> a.sharpOrder).reversed());
System.out.println(Arrays.toString(cards));
selection(cards, Comparator.comparingInt((Card a) -> a.numberOrder).reversed());
System.out.println(Arrays.toString(cards));

System.out.println("=================稳定=================");
cards = getStaticCards();
System.out.println(Arrays.toString(cards));
bubble(cards, Comparator.comparingInt((Card a) -> a.sharpOrder).reversed());
System.out.println(Arrays.toString(cards));
bubble(cards, Comparator.comparingInt((Card a) -> a.numberOrder).reversed());
System.out.println(Arrays.toString(cards));

都是先按照花色排序(♠♥♣♦),再按照数字排序(AKQJ...)

  • 不稳定排序算法按数字排序时,会打乱原本同值的花色顺序

    [[♠7], [♠2], [♠4], [♠5], [♥2], [♥5]]
    [[♠7], [♠5], [♥5], [♠4], [♥2], [♠2]]
    

    原来 ♠2 在前 ♥2 在后,按数字再排后,他俩的位置变了

  • 稳定排序算法按数字排序时,会保留原本同值的花色顺序,如下所示 ♠2 与 ♥2 的相对位置不变

    [[♠7], [♠2], [♠4], [♠5], [♥2], [♥5]]
    [[♠7], [♠5], [♥5], [♠4], [♠2], [♥2]]
    

大家多多讨论学习salute

image.png