分析
如上图,列表分为两部分,黄色代表排序过的有序区,蓝色代表未排序的无序区,循环遍历无序区,选出最小的元素,放在无序区的头部,此时无序区的头部变为排序区。
拿[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,忘记了。。。