js实现冒泡排序的三种方法

1,826 阅读2分钟

方法一

相邻元素两两比较,当一个元素大于右侧相邻元素时,交换它们的位置,当一个元素小于或等于右侧相邻元素时,位置不变。

/**
 * 
 * @param {待排序数组} arr 
 * 时间复杂度:O(n^2)
 * 稳定排序(相邻元素相等时不交换位置)
 * 空间复杂度:O(1) 直接修改原数组
 */
function bubbleSort(arr) {
  for (let i = 0; i < arr.length - 1; i++) {
    for (let j = 0; j < arr.length - i - 1; j++) {
      if (arr[j] > arr[j + 1]) {
        // 利用数组解构赋值 交换j和j+1
        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
      }
    }
  }
}

方法二

这是对方法一的优化版,增加有序标记,如果某一轮比较,一个元素都没有交换就代表整个数组已经有序。

/**
 * 
 * @param {待排序数组} arr 
 */
function bubbleSort(arr) {
  for (let i = 0; i < arr.length - 1; i++) {
    // 有序标记,每一轮的初始值都是true
    let isSorted = true;
    for (let j = 0; j < arr.length - i - 1; j++) {
      if (arr[j] > arr[j + 1]) {
        // 利用数组解构赋值 交换j和j+1
        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
        // 进这个if循环,就代表有元素进行交换,所以就不是有序的,把标记改为false
        isSorted = false;
      }
    }
    if (isSorted) {
      break;
    }
  }
}

方法三

这是对方法一的进一步优化,优化每一轮比较的次数。增加一个border代表无序边界,然后把最后一次发生元素交换的位置点记下来,下一轮比较就只需要比到这儿为止。

/**
 *
 * @param {待排序数组} arr
 */
function bubbleSort(arr) {
  //  记录最后一次交换的边界
  let lastExchangeIndex = 0;
  //  无序数组的边界,每次比较只需要比到这里为止
  let sortBorder = arr.length - 1;
  for (let i = 0; i < arr.length - 1; i++) {
    // 有序标记,每一轮的初始值都是true
    let isSorted = true;
    for (let j = 0; j < sortBorder; j++) {
      if (arr[j] > arr[j + 1]) {
        // 利用数组解构赋值 交换j和j+1
        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
        // 进这个if循环,就代表有元素进行交换,所以就不是有序的,把标记改为false
        isSorted = false;
        // 更新为最后一次交换元素的位置
        lastExchangeIndex = j;
      }
    }
    sortBorder = lastExchangeIndex;
    if (isSorted) {
      break;
    }
  }
}

方法四:鸡尾酒排序

鸡尾酒排序算法相比冒泡排序差别点就在,鸡尾酒是双向排序。就像排钟从左摆到右后,立即从当前位置摆回去。

缺点:代码复杂

适用场景:大部分元素已经有序,摆几下就能完全有序

/**
 *
 * @param {待排序数组} arr
 */
function bubbleSort(arr) {
  for (let i = 0; i < arr.length / 2; i++) {
    // 有序标记,每一轮的初始值都是true
    let isSorted = true;
    for (let j = i; j < arr.length - i - 1; j++) {
      if (arr[j] > arr[j + 1]) {
        // 利用数组解构赋值 交换j和j+1
        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
        // 进这个if循环,就代表有元素进行交换,所以就不是有序的,把标记改为false
        isSorted = false;
      }
    }
    if (isSorted) {
      break;
    }
    // 顺摆轮结束之前,把isSorted重新标记为true,下面就开始逆摆
    isSorted = true;
    for (let j = arr.length - i - 1; j > i; j--) {
      if (arr[j] < arr[j - 1]) {
        // 利用数组解构赋值 交换j和j+1
        [arr[j], arr[j - 1]] = [arr[j - 1], arr[j]]
        // 进这个if循环,就代表有元素进行交换,所以就不是有序的,把标记改为false
        isSorted = false;
      }
    }
    if (isSorted) {
      break;
    }
  }
}