排序算法(1):冒泡排序

23 阅读4分钟

前言

一般而言,我看书中算法,写的顺序都是从小到大排序。当然,稍加改变代码就能实现从大到小。那么就默认从小到大(递增)的排序方式吧。

先从最简单的排序算法——冒泡排序开始吧

冒泡排序原理:

先把第一个数字抽出来与第二个数字相比,如果第一个数字大于第二个数字,那么它两交换位置,如果小于或等于那么顺序不变。同样的操作然后再从第二个数字与第三个数字相比。这样操作后,数组中最大的数字就确定好位置在数组的最后面 以上操作重复,那么就把第二大的数字确定下来,放到了数组中倒数第二的位置 那么要重复几次这种操作呢。数组中有几个数,就重复几次。

举例

给一个乱序的数组:[5,8,2,3]

第一次:[5,8,2,3]

从第1个数字开始: 5>8? no 不换位置 [5,8,2,3]

从第2个数字开始:8>2? yes 换位置 [5,2,8,3]

从第3个数字开始:8>3? yes 换位置 [5,2,3,8]

第二次:[5,2,3,8]

从第1个数字开始: 5>2? yes 换位置 [2,5,3,8]

从第2个数字开始:5>3? yes 换位置 [2,3,5,8]

从第3个数字开始:5>8? no 不换位置 [2,3,5,8]

第三次:[2,3,5,8]

从第1个数字开始: 2>3? no 不换位置 [2,3,5,8]

从第2个数字开始:3>5? no 不换位置 [2,3,5,8]

从第3个数字开始:5>8? no 不换位置 [2,3,5,8]

第四次:[2,3,5,8]

从第1个数字开始: 2>3? no 不换位置 [2,3,5,8]

从第2个数字开始:3>5? no 不换位置 [2,3,5,8]

从第3个数字开始:5>8? no 不换位置 [2,3,5,8]

小结:

数组有几个数,就要遍历几次。每次比对都从第一个数开始,两两比对,数值大的往后放。那么第一次遍历结果就将最大的数放在最后。每次遍历都是相同操作,自然就组成一个升序的数组。

  • 遍历次数与数组的长度相等
  • 内部比对的次数,因为不用自己和自己比,所以是长度-1。这从举例中也可看出。

代码

js代码

function bubbleSort(array) {
  for (let i = 0; i < array.length; i++) {
    for (let j = 0; j < array.length - 1; j++) {
      if (array[j] > array[j + 1]) {
        // 这是es6推出的解构语法,在数组中值交换时非常方便。
        [array[j],array[j+1]]=[array[j+1],array[j]]

        // 不然就需要一个临时变量来接
        // let tem = array[j];
        // array[j] = array[j + 1];
        // array[j + 1] = tem;        
      }
    }
    
  }
  return array;
}
const a = [5, 8, 2, 3];
const b = bubbleSort(a);
console.log(b);

image.png

ts 代码

function bubbleSort<T>(array:T[]){
    for (let i = 0; i < array.length; i++) {
        for (let j = 0; j < array.length - 1; j++) {
          if (array[j] > array[j + 1]) {           
            [array[j],array[j+1]]=[array[j+1],array[j]]                
          }
        }
        
      }
      return array;
}

优化

我们观察发现。

第一次比较时已经将最大的数值8找出,放在了数组的最后。此时 i=0

第二次比较时,与最后8的数值就没有必要比了,可以减少一次比较。并且将第二大的数值5找出放在了数组倒数第二的位置上 此时 i=1

第三次比较时,最大与第二大的数值排好了,就不要再与它们比了,减少两次比较,并且将第三大的数值3找出放在了数组倒数第三的位置上 此时 i=2

第四次比较时,最大与第二大与第三大的数值排好了,就不要再与它们比了,减少三次比较,并且将第四大的数值2找出放在了数组倒数第四的位置上 此时 i=3

等一下,再想想,总共4个数,第三次比较时,已经确定好了最大三个数的位置。第四个数就是最小的数值,它的位置就正好在第一个,所以第四次比较就没必要了。

所以要修改两处。

function bubbleSort(array) {

// 第一处修改,最后一次的遍历没必要,因为剩余的数值都从小到大排好了,最小的数值就正好排在第一位上
  for (let i = 0; i < array.length-1; i++) {
  
   // 第一处修改 array.length-1还要减去i,这样每一次外层的遍历都会少i次
    for (let j = 0; j < array.length - 1-i; j++) {
    
      if (array[j] > array[j + 1]) {
        // 这是es6推出的解构语法,在数组中值交换时非常方便。
        [array[j],array[j+1]]=[array[j+1],array[j]]

        // 不然就需要一个临时变量来接
        // let tem = array[j];
        // array[j] = array[j + 1];
        // array[j + 1] = tem;        
      }
    }
    
  }
  return array;
}
const a = [5, 8, 2, 3];
const b = bubbleSort(a);
console.log(b);