在开始之前,我们同样来看一下选择排序的过程:
从图中我们可以得出:
选择排序是将数组分成了两部分,一部分是已排序,一部分是未排序;
遍历未排序数组,从中选择最小/最大的元素,将其放在已排序数组的末尾。或者也可以说是把未排序数组中的最小/最大的元素跟未排序中的第一位交换位置;
循环执行第二步,直到所有数字都完成排序。
我们以数组[5,15,12,3,19,4,22]为例,看一下每一轮的变化:
let arr = [5,15,12,3,19,4,22]
let min // 每一轮未排序数组最小值的下标
let notSortFirst // 每一轮中未排序数组的第一个的下标
// 第一轮:
// 未排序数组的第一个数字为5,下标为0
notSortFirst = 0
// 未排序数组中最小值为3,下标为3
min = 3
// 交换两个下标数字的位置 swap(0,3),数组变成:
[3,15,12,5,19,4,22]
// 第二轮
// 未排序数组的第一个数字为15,下标为1
notSortFirst = 1
// 未排序数组中最小值为4,下标为5
min = 5
// 交换两个下标数字的位置 swap(1,5),数组变成:
[3,4,12,5,19,15,22]
// 第三轮
// 未排序数组的第一个数字为12,下标为2
notSortFirst = 2
// 未排序数组中最小值为5,下标为3
min = 3
// 交换两个下标数字的位置 swap(2,3),数组变成:
[3,4,5,12,19,15,22]
// 第四轮
// 未排序数组的第一个数字为12,下标为3
notSortFirst = 3
// 未排序数组中最小值为12,下标为3
min = 3
// 交换两个下标数字的位置 swap(3,3),数组变成:
[3,4,5,12,19,15,22]
// 第五轮
// 未排序数组的第一个数字为19,下标为4
notSortFirst = 4
// 未排序数组中最小值为15,下标为5
min = 5
// 交换两个下标数字的位置 swap(4,5),数组变成:
[3,4,5,12,15,19,22]
// 第六轮
// 未排序数组的第一个数字为19,下标为5
notSortFirst = 5
// 未排序数组中最小值为19,下标为5
min = 5
// 交换两个下标数字的位置 swap(5,5),数组变成:
[3,4,5,12,15,19,22]
// 第七轮
// 未排序数组的第一个数字为22,下标为6
notSortFirst = 6
// 未排序数组中最小值为22,下标为6
min = 6
// 交换两个下标数字的位置 swap(6,6),数组变成:
[3,4,5,12,15,19,22]
// 数组排序完成
从上面步可以看出,每一轮中未排序数组的第一项是从0一直增加到数组的最后一项的,而找最小值也是可以直接从未排序数组第一项的后一个开始找起,所以双重for循环可以这样写:
let arr = [5,15,12,3,19,4,22]
let min // 每一轮未排序数组最小值的下标
let notSortFirst // 每一轮中未排序数组的第一个的下标
for(let i = 0;i<arr.length;i++){
notSortFirst = i
for(let j = i+1;j<arr.length;j++){
// 在这个循环里面找到最小值,存储它的下标
}
// 在这里将找到的最小值与未排序的第一个进行交换
swap(notSortFirst,min)
}
我们发现notSortFirst就是每一轮中的i,所以可以直接使用i进行交换;而最后一轮只剩下一个数字,是可以不用排序的,所以外层循环可以只到length-1:
let arr = [5,15,12,3,19,4,22]
let min // 每一轮未排序数组最小值的下标
for(let i = 0;i<arr.length-1;i++){
for(let j = i+1;j<arr.length;j++){
// 在这个循环里面找到最小值,存储它的下标
}
// 在这里将找到的最小值与未排序的第一个进行交换
swap(i,min)
}
我们在找最小值的时候是需要有一个值进行对比才行,也就是min需要有一个默认值,在内层循环中将每一项与min进行比较,如果比min对应的值小,就给min重新赋值。那min的默认值我们就可以设置成未排序数组的第一项:
let arr = [5,15,12,3,19,4,22]
let min // 每一轮未排序数组最小值的下标
for(let i = 0;i<arr.length-1;i++){
min = i
for(let j = i+1;j<arr.length;j++){
// 在这个循环里面找到最小值,存储它的下标
if(arr[j] < arr[min]){
min = j
}
}
// 在这里将找到的最小值与未排序的第一个进行交换
swap(i,min)
}
console.log(arr)
现在就是要实现数字的交换,我们可以像上一张冒泡排序一样直接在for循环里面写,但是在排序中我们很多地方都会用到数组的交换,可以提取成一个方法放到数组的原型上:
Array.prototype.swap = function(originIndex,targetIndex){
let temp = this[originIndex]
this[originIndex] = this[targetIndex]
this[targetIndex] = temp
}
let arr = [5,15,12,3,19,4,22]
let min // 每一轮未排序数组最小值的下标
for(let i = 0;i<arr.length-1;i++){
min = i
for(let j = i+1;j<arr.length;j++){
// 在这个循环里面找到最小值,存储它的下标
if(arr[j] < arr[min]){
min = j
}
}
// 在这里将找到的最小值与未排序的第一个进行交换
// 只有当i与min值不同的时候才交换
i!==min && arr.swap(i,min)
}
console.log(arr) // [3, 4, 5, 12, 15, 19, 22]
以上就是选择排序的实现了。