vlambda博客
学习文章列表

经典算法动画解析系列:选择排序

哈喽,我是「程序员大鹏」。

上一篇我们介绍了,今天我们再介绍另外一个经典的排序算法「简单选择排序」,简单选择排序也叫直接选择排序,是最基本的选择排序方法。

选择排序思想

基本思想

实现思想是每步从排序记录中选出排序码最小(最大)的记录,放在已排序记录序列的最后(前);

算法特点

直接选择排序算法n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果。

排序原理

  1. 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置
  2. 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
  3. 重复第二步,直到所有元素均排序完毕。

选择排序动画


选择排序代码

  public static void selectionSort(int[] arr) {
    int min, temp;
    for (int i = 0; i < arr.length ; i++) {
      // 初始化最小下标为最小数据数组下标
      min = i;
      for (int j = i + 1; j < arr.length; j++) {
        // 在未排序元素中继续寻找最小元素,并保存其下标
        if (arr[j] < arr[min]) {//如果有小于当前最小值的值
          min = j;//将此数值的下标赋值给min
        }
      }
      if (min != i) {// 如果min不等于i,说明找到最小值,进行交换
        //数据交换
        temp = arr[min];
        arr[min] = arr[i];
        arr[i] = temp;
      }
    }
  }

让我们来一行一行地分析一下代码:

for (int i = 0; i < arr.length ; i++) {

在上面代码是外层循环,在刚开始的时候,先记录下来当前最小值的索引,也就是i的值。

min = i;

每一轮开始的时候,min的值就是起点的索引,也就是未排序数据的起始索引,第一轮为0,第二轮是1,第三轮是2,依次类推,一直到最后一轮。

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

开始内层的循环

        if (arr[j] < arr[min]) {
          min = j;
        }

依次检查未排序的数据,如果遇到的值比索引为min的值小,则将min更新为这个数据的索引。当内层循环完毕时,min就是是当前轮的最小值的索引。

      if (min != i) {
        temp = arr[min];
        arr[min] = arr[i];
        arr[i] = temp;
      }

判断min与初始值i比较,如果不一样,说明最小值不是第一个,则将索引为i的值与索引为min的值进行交换。

选择排序复杂度分析

容易看出,待排序序列为正序,移动次数最小,为 0 次;待排序序列为逆序时,移动次数最多,为 3(n-1) 次。

但无论记录的初始排列如何,关键码的比较次数相同,第 i 趟排序需进行 n-i 次关键码的比较,而简单选择排序需要进行 n-1 趟排序,因此,总的比较次数为 O(n^2)

故而,无论是最优、最差时间复杂度,还是平均时间复杂度,均为 O(n^2)

对于空间复杂度来说,简单选择排序仅需一个存储空间用于记录交换的暂存单元,即空间复杂度为 O(1)。