Code前端首页关于Code前端联系我们

JavaScript数据结构与算法:冒泡排序及其优化方法

terry 2年前 (2023-09-27) 阅读数 162 #数据结构与算法

基本概念

冒泡排序是一种基本的排序算法。基本思想是通过不断比较相邻元素并在必要时交换它们,将最大(或最小)元素“冒险”到序列的一端。

排序步骤

首先来体验一下冒泡排序的步骤

我们以集合[5,3,8,4,6]为例。冒泡排序的步骤如下:

  • 第一轮排序:

比较相邻元素。当我们首先比较5和3时,5大于3,我们交换它们,矩阵变成[3,5,8,4,6];然后比较5和8,5小于8,不需要交换,再比较8和4,8大于4,交换,数组变成[3, 5, 4, 8, 6] ;最后比较8和6,8大于6,交换,矩阵变为[3,5,4,6,8]。就这样,经过第一轮的比较,数量最高的8名排在了最后。

  • 第二轮排序:

再次从前到后比较相邻元素。这次由于8已经是末尾最大的元素,所以不再纳入比较。首先比较3和5,3小于5,不需要交换;然后比较5和4,5大于4,交换,字符串变成[3,4,5,6,8];然后比较5和5 6.5小于6不需要交换。这样,第二轮排序就完成了,第二大元素6也放到了它应该在的地方。

  • 下一轮排序:

如此重复,每轮比较的元素对数量比上一轮少一个。直到全部排序完毕。

最后,字符串 [5, 3, 8, 4, 6] 被排序为 [3, 4, 5, 6, 8]

冒泡排序实现

let array = [5, 3, 8, 4, 6];

for(let i = 0; i < array.length; i++) {
  for(let j = 0; j < array.length - i - 1; j++) {
    if(array[j] > array[j + 1]) {
      // 交换元素
      let temp = array[j];
      array[j] = array[j + 1];
      array[j + 1] = temp;
    }
  }
}

console.log(array);  // 输出: [3, 

4, 5, 6, 8]

该算法的时间复杂度为O(n^2),因此在处理大量数据时可能效率较低。

优化策略

替换标志

如果过渡过程中没有发生替换,则说明序列已经没问题,无需进一步排序。可以通过设置标志来优化算法。如果在给定的转换期间没有发生交换,则排序直接结束。

这种优化可以极大地提高已经部分排序的序列的性能。

let array = [5, 3, 8, 4, 6];
let swapped = true;

while(swapped) {
  swapped = false;
  for(let i = 0; i < array.length - 1; i++) {
    if(array[i] > array[i + 1]) {
      let temp = array[i];
      array[i] = array[i + 1];
      array[i + 1] = temp;
      swapped = true;
    }
  }
}

console.log(array);  // 输出: [3, 4, 5, 6, 8]

双向冒泡排序

一次遍历只能保证最大(或最小)的数移动到序列的一端。双向冒泡排序中,一次遍历涉及两个过程,一个端到端,一个端到端开始,这样可以保证遍历一遍后最大和最小的数都移动到正确的位置。

let array = [5, 3, 8, 4, 6];
let swapped;
let start = 0;
let end = array.length - 1;

while(start < end) {
  for(let i = start; i < end; i++) {
    if(array[i] > array[i + 1]) {
      let temp = array[i];
      array[i] = array[i + 1];
      array[i + 1] = temp;
      swapped = i;
    }
  }
  end = swapped;

  for(let i = end; i > start; i--) {
    if(array[i] < array[i - 1]) {
      let temp = array[i];
      array[i] = array[i - 1];
      array[i - 1] = temp;
      swapped = i;
    }
  }
  start = swapped;
}

console.log(array);  // 输出: [3, 4, 5, 6, 8]

记录最后一次交换的位置

在实际的数据序列中,末尾通常会有多个有序序列,这样我们就可以记住最后一次交换发生的位置,并在下次与该位置进行比较。

let array = [5, 3, 8, 4, 6];
let lastExchangeIndex = 0;
let sortBorder = array.length - 1;

for(let i =

 0; i < array.length - 1; i++) {
  let isSorted = true;
  for(let j = 0; j < sortBorder; j++) {
    if(array[j] > array[j + 1]) {
      let temp = array[j];
      array[j] = array[j + 1];
      array[j + 1] = temp;
      
      isSorted = false;
      lastExchangeIndex = j;
    }
  }
  sortBorder = lastExchangeIndex;
  if(isSorted) {
    break;
  }
}

console.log(array);  // 输出: [3, 4, 5, 6, 8]

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

热门