算法——多语言实现选择排序

326 阅读2分钟

分析

img

如上图,列表分为两部分,黄色代表排序过的有序区,蓝色代表未排序的无序区,循环遍历无序区,选出最小的元素,放在无序区的头部,此时无序区的头部变为排序区。

[9, 1, 6, 4, 5, 7, 2, 3, 8]举例,整个列表都未排序所以都是无序区,所以下标0的位置就是无序区的表头,循环一次无序区,选出最小的元素,即下标为1的位置上的元素1,要把下标为1的元素1放在表头,就需要和表头元素交换位置,而此时表头是下标为0的元素9,所以交换位置,列表变成了[1, 9, 6, 4, 5, 7, 2, 3, 8]。此时第一个位置已经是排序过的最小值,有序区有了第一个元素,无序区减少一个元素。

数组有序区无序区(循环区域)
初始状态:[9, 1, 6, 4, 5, 7, 2, 3, 8][][9, 1, 6, 4, 5, 7, 2, 3, 8]
第一次循环:[1, 9, 6, 4, 5, 7, 2, 3, 8][1][9, 6, 4, 5, 7, 2, 3, 8]
第二次循环:[1, 2, 6, 4, 5, 7, 9, 3, 8][1, 2,][6, 4, 5, 7, 9, 3, 8]
第三次循环:[1, 2, 3, 4, 5, 7, 9, 6, 8][1, 2, 3,][4, 5, 7, 9, 6, 8]
第四次循环:[1, 2, 3, 4, 5, 7, 9, 6, 8][1, 2, 3, 4, ][5, 7, 9, 6, 8]
第五次循环:[1, 2, 3, 4, 5, 7, 9, 6, 8][1, 2, 3, 4, 5, ][7, 9, 6, 8]
第六次循环:[1, 2, 3, 4, 5, 6, 9, 7, 8][1, 2, 3, 4, 5, 6, ][9, 7, 8]
第七次循环:[1, 2, 3, 4, 5, 6, 7, 9, 8][1, 2, 3, 4, 5, 6, 7, ][9, 8]
第八次循环:[1, 2, 3, 4, 5, 6, 7, 8, 9][1, 2, 3, 4, 5, 6, 7, 8, ][9]
第九次循环:[1, 2, 3, 4, 5, 6, 7, 8, 9][1, 2, 3, 4, 5, 6, 7, 8, 9][]

Dart 实现

把上面的分析用代码实现:

每次循环即外层循环,找出无序区最小元素,是内循环。

void selectSortLow(List<int> list) {
  var minIndex = 0;
  for (var i = 0; i < list.length; i++) {
    for (var j = i; j < list.length; j++) {
      if (list[j] < list[minIndex]) {
        minIndex = j;
      }
    }
    var temp = list[i];
    list[i] = list[minIndex];
    list[minIndex] = temp;
  }
}

void main(List<String> args) {
  var list = [9, 1, 6, 4, 5, 7, 2, 3, 8];
  selectSortLow(list);
  print(list);
}

优化

第八次循环的结果和第九次循环的结果一样,可以看出第八次循环中,无序区只剩余一个元素,这个元素也是最大的,所以不需要再次循环,所以,将上面的算法去掉一次循环:

void selectSortLow(List<int> list) {
  var minIndex = 0;
  for (var i = 0; i < list.length-1; i++) {
    for (var j = i; j < list.length; j++) {
      if (list[j] < list[minIndex]) {
        minIndex = j;
      }
    }
    var temp = list[i];
    list[i] = list[minIndex];
    list[minIndex] = temp;
  }
}

默认最小值的下标为0,所以第一次内部循环,就不需要从0开始循环,直接从1开始:

void selectSortLow(List<int> list) {
  var minIndex = 0;
  for (var i = 0; i < list.length-1; i++) {
    for (var j = i+1; j < list.length; j++) {
      if (list[j] < list[minIndex]) {
        minIndex = j;
      }
    }
    var temp = list[i];
    list[i] = list[minIndex];
    list[minIndex] = temp;
  }
}

通过两次优化,减少2次循环。

kotlin

fun selectSortLow(list: MutableList<Int> ) {
    var minIndex = 0
    for (i in 0 until list.size - 1) {
        for (j in i + 1 until list.size) {
            if (list[j] < list[minIndex]) {
                minIndex = j
            }
        }
        val temp = list[i]
        list[i] = list[minIndex]
        list[minIndex] = temp
    }
}

Python

def select_sort(li):
    for i  in range(len(li)-1):
        min_index=i
        for j  in range(i+1,len(li)):
            if(li[j]<li[min_index]):
                min_index=j
        li[i],li[min_index]=li[min_index],li[i]

总结

第一次循环记录最小元素的下标,放到第一个位置。

第二次记录未排序区最小元素的下标,放到第二个位置。。。

关键点:有序区、无序区、最小值小标

没有js,因为N多年没有写过js,忘记了。。。