【算法四】排序算法之选择排序

冒泡排序是通过两两比较,不断交换,逐个推进,一轮遍历得到一个最值的方式来排序的。
冒泡排序算法费时的:一是两两比较;二是两两交换。
冒泡排序两两交换的目的就是为了找出最值。但是通过这种方式取得最值代价是很大的,因为每次遍历,都需要很多次的交换才能找到最值,而这些交换操作都是很浪费时间的。
如果能减少交换次数,同时又能找到最值,那么这就是一种改进。可以每次遍历,只选择最值元素进行交换,这样一次遍历只需要进行一次交换即可,避免了其他无价值的交换操作。

选择排序(Selection Sort):是一种简单的排序算法,也是一种不稳定的排序算法。其实现原理是:在待排序序列中不断进行比较,一轮遍历选出一个最值,将其按顺序存放在已排序序列中;重复此步骤,直到待排序序列中的数据都排序完毕。
请添加图片描述

选择排序的示例:

假设待排序序列为 5、3、6、1、0,如果采用选择排序对其进行升序排序,则整个排序过程如下所示:
在这里插入图片描述

  1. 第一轮遍历:在待排序序列 5、3、6、1、0 中找到最小值 0,并将其与 5 进行交换,此时待排序序列为 3、6、1、5,已排序序列为 0。
  2. 第二轮遍历:在待排序序列 3、6、1、5 找到最小值 1,并将其与数组的 3 进行交换,此时待排序序列为 6、3、5,已排序序列为 0、1。
  3. 第三轮遍历:在待排序序列 6、3、5 中找到最小值 3,并将其与数组的第一位 6 进行交换,此时待排序序列为 6、5,已排序序列为 0、1、3。
  4. 第四轮遍历:在待排序序列 6、5 中找到最小值 5,并将其与 6 进行交换,此时待排序序列为 6,已排序序列为 0、1、3、5。
  5. 当进行第五轮遍历时,由于待排序序列中仅剩 1 个元素,因此直接将其并入已排序序列中,此时的序列就为已排序好的序列。

选择排序的效率:

选择排序改进了冒泡排序,将交换的次数由 O(n²) 减少到 O(n),但是比较的次数仍然是 O(n²)。通常认为选择排序在执行效率上是高于冒泡排序的。

比较次数:

上面的例子一共有 5 个数字,第一轮遍历进行了 4 次比较,第二轮遍历进行了 3 次比较,第三轮遍历进行了 2 次比较,第四轮遍历进行了 1 次比较,比较次数为:4 + 3 + 2 + 1

假设有 n 个数据项,推导公式为:(n - 1) + (n - 2) + (n - 3)+ ... +1 = n * (n - 1) / 2,因此选择排序真实的比较次数为 n * (n - 1) / 2

n * (n - 1) / 2 = n² / 2 - n / 2 ,根据推导大 O 表示法的规则 2 只保留最高阶项,变为 n² / 2,根据规则 3 去除最高阶项的常量,变为 ,因此选择排序的比较次数的大 O 表示法为 O(n²)

交换次数:

每轮遍历找到最小值最多交换一次,一共需要遍历 n - 1 次,因此选择排序真实的交换次数为 n - 1

由于常量不算在大 O 表示法中,因此选择排序的交换次数的大 O 表示法为 O(n)

选择排序的代码实现:

需要两层循环来实现:

  1. 外层循环是有 n 个元素就进行 n -1 次内层循环,寻找 n -1 遍最值。
  2. 内层循环是通过比较找出最值,然后将其与被遍历数据中的第一位进行交换,也就将其排到了已找到的最值中的最后一位。

    下一次进行内层循环的时候就不需要比较已被找到的最值了,因此内层循环遍历的数据量是依次递减的。

// 选择排序:升序
ArrayList.prototype.selectionSort = function () {
  // 1. 获取列表长度
  var length = this.array.length

  // 2. 外层循环:从第 0 个位置开始,依次遍历到 length - 2 的位置,只剩最后一个值的时候就不需要再进行遍历了
  for (var i = 0; i < length - 1 ; i++) {
    // 3. 定义一个变量,用于记录最小值的位置
    // 每次内层循环都能找到一个最值并将其放置到前端,因此,之后的遍历就不需要再操作已找到的最值了。执行第几次的外层循环,内层循环就从几开始,定义最小值的下标值就为几。
    var minIndex = i

    // 4. 内层循环:从 i + 1 的位置开始,和 i 位置的数据进行比较,直到 length - 1 的位置,找到最小值所在的位置
    for (var j = i + 1; j < length; j++) {
      if (this.array[j] < this.array[minIndex]) {
        minIndex = j
      }
    }
    
    // 5. 将最小值与 i 位置的数据替换
    this.swap(minIndex, i)
  }
}

// 测试选择排序:
list.selectionSort()
console.log(list.toString()) // 1 2 4 5 8
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值