冒泡排序与优化 如何实现最优时间复杂度为O(n)的冒泡排序

冒泡排序与优化

冒泡排序是一种简单经典的排序,通过比较相邻位置,在第n趟比较结束之后即可确定第n大/小的值,比较结束后全部元素按照顺序排列

时间复杂度
平均时间复杂度为O(n²),最优为O(n),属于性能比较差的排序方式

空间复杂度
由于只在数组里面进行元素位置的交换,属于原地排序,不分配额外内存空间,因此空间复杂度较为优越为O(1)

是否稳定
由于只对大小不等的元素进行位置互换,不会操作大小相同的元素,所以对于相同元素的子序列,在排序之后依然拥有相同的索引位置,属于稳定排序

初步实现

function bubleSort(arr) {
  if (!isSortable(arr)) return arr
  for (let i = 0; i < arr.length; i++)
    for (let j = 0; j < arr.length; j++)
      arr[j] > arr[j + 1] && arr.splice(j, 1, ...arr.splice(j + 1, i, arr[j]))
}

冒泡排序优化

  1. 常量提取
    在排序时,数组的长度固定,因此可以作为常量提取出来,避免在arr中对length属性进行频繁地访问,降低开销

  2. 优化遍历次数
    相邻比较,即从数组的起始两个位置arr[0],arr[1],一直比较到数组末尾两个位置arr[length-2],arr[length-1],即j+1的取值范围在[0,length-1]即可,j<length-1
    再者,如果从内循环减去外循环中已跑过的轮数,就可以避免内循环中所有不必要的比较。j < (length-1) - i ,i为比较的趟数。(即第n趟排序已经确定了第n大的值,后续不需要再对其进行比较了)

function bubleSort(arr) {
  if (!isSortable(arr)) return arr
  const { length } = arr
  for (let i = 0; i < length - 1; i++)
    for (let j = 0; j < (length - i) - 1; j++)
      arr[j] > arr[j + 1] && arr.splice(j, 1, ...arr.splice(j + 1, 1, arr[j]))
}

拓展 如何使用一层for循环实现冒泡排序

冒泡排序的实现思路是对不定顺序的子序列通过相邻比较和位置交换来确定大小顺序,尽管一般实现使用了两层for循环,但只要控制好索引,用一层for循环实现也未尝不可
尽管只使用了一次for循环,但也只是换一种写法而已,它的时间复杂度依然是O(n²)

function singleLoopBuble(arr) {
  if (!isSortable(arr)) return arr
  let max = arr.length - 1
  for (let j = 0; j < max; j++) {
    arr[j] > arr[j + 1] && arr.splice(j, 1, ...arr.splice(j + 1, 1, arr[j]))
    // j = -1 让j<length成立,循环继续, for循环条件判断之后的j++又让j从0开始
    j + 1 === max && (j = -1) && max --
  }
}

如何实现最优时间复杂度为O(n)的冒泡排序

最优情况O(n)
如果第一趟比较中,所有元素就是有序的,那么说明整个数组就是有序的,后续也无需再进行比较。此时只进行了第一趟比较,只执行了一趟内循环,因此时间复杂度是O(n)
只要不满足上述场景,那么外循环依旧要执行,时间复杂度依然为O(n²)

function perfectBuble(arr) {
  if (!isSortable(arr)) return arr
  const { length } = arr
  for (let i = 0; i < length - 1; i++) {
    let didSwap = false
    for (let j = 0; j < length - i - 1; j++) {
      if (arr[j] > arr[j + 1]) {
          // 仅在第一趟比较时进行判断
          arr.splice(j, 1, ...arr.splice(j + 1, 1, arr[j]))
          didSwap = true
      }
    }
    if(!didSwap) return
  }
}

辅助函数

判断是否可排序

function isSortable(arr){
    return Array.isArray(arr) && arr.length > 1
}
posted @ 2022-04-11 19:15  IslandZzzz  阅读(192)  评论(0编辑  收藏  举报