选择排序的实现、效率

98 阅读2分钟

这是我参与2022首次更文挑战的第30天,活动详情查看:2022首次更文挑战

选择排序的实现

以下是用Javascript写的选择排序。

function selectionSort(array){
  for(var i=0; i < array.length; i++){
   var lowestNumberIndex=i;
   for(var j=i+1; j < array.length; j++){
    if(array[j] < array[lowestNumberIndex]){
     lowestNumberIndex=j;
    }
   }

   if(lowestNumberIndex != i){
    var temp=array[i];
    array[i]=array[lowestNumberIndex];
    array[lowestNumberIndex]=temp;
   }
  }
  return array;
}

让我们来一行行地分析。我会先摘出代码片段,然后给出解释。

for(var i=0; i < array.length; i++){

这个外层的循环代表每一轮检查。在一轮检查之初,我们会先记住目前的最小值的索引。

var lowestNumberIndex=i;

因此每轮开始时lowestNumberIndex都会是该轮的起点索引i。注意我们实际上记录的是最小值的索引,而非最小值本身。于是,第1轮开始时最小值的索引是0,到第2轮则是1,以此类推。

for(var j=i+1; j < array.length; j++){

因此每轮开始时lowestNumberIndex都会是该轮的起点索引i。注意我们实际上记录的是最小值的索引,而非最小值本身。于是,第1轮开始时最小值的索引是0,到第2轮则是1,以此类推。


for(var j=i+1; j < array.length; j++){

此行代码发起一个以i+1开始的内层循环。

if(array[j] < array[lowestNumberIndex]){   lowestNumberIndex=j; }

循环内逐个检查数组未排序的格子,若遇到比之前记录的本轮最小值还小的格子值,就将lowestNumberIndex更新为该格子的索引。

内层循环结束时,会得到未排序数值中最小值的索引。

if(lowestNumberIndex != i){   var temp=array[i];   array[i]=array[lowestNumberIndex];   array[lowestNumberIndex]=temp; }

然后再看看这个最小值是否已在正确位置,即该索引是否等于i。如果不是,就将i所指的值与最小值交换。

选择排序的效率

选择排序的步骤可分为两类:比较和交换,也就是在每轮检查中把未排序的值跟该轮已遇到的最小值做比较,以及将最小值与该轮起点的值交换以使其位置正确。

在之前5个元素的例子里,我们总共进行了10次比较。每轮分别如下。

于是 4+3+2+1=10次比较。

推广开来,若有个元素,就会有 次比较。

但每轮的交换最多只有1次。如果该轮的最小值已在正确位置,就无须交换,否则要做1次交换。相比之下,冒泡排序在最坏情况(完全逆序)时,每次比较过后都要进行1次交换。

下表为冒泡排序和选择排序的并列对比。

从表中可以清晰地看到,选择排序的步数大概只有冒泡排序的一半,即选择排序比冒泡排序快一倍。