你确定懂冒泡排序?用动画的方式讲懂冒泡排序及其优化方式

冒泡排序是一种基础排序算法,通过比较相邻元素并交换来排序。文章详细描述了冒泡排序的步骤,以数组示例解释,并提供了JavaScript实现。还讨论了优化策略,如交换标记、双向冒泡排序以及记录交换位置,以提高效率。
摘要由CSDN通过智能技术生成
点击在线阅读,体验更好链接
现代JavaScript高级小册链接
深入浅出Dart链接
现代TypeScript高级小册链接

基本概念

冒泡排序是一种基础的排序算法。其基本思想是通过不断地比较相邻元素并在必要时进行交换,将最大(或最小)的元素"冒"到序列的一端。

排序步骤

先来感受到冒泡排序的步骤吧

以数组 [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和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]
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
这里给出一个使用Java Swing实现冒泡排序UI动画的示例代码: ```java import javax.swing.*; import java.awt.*; import java.util.Random; public class BubbleSortAnimation extends JFrame { private static final int ARRAY_SIZE = 50; private static final int WINDOW_WIDTH = 800; private static final int WINDOW_HEIGHT = 600; private static final int BAR_WIDTH = 10; private static final int BAR_HEIGHT_MULTIPLIER = 10; private static final int DELAY = 50; private int[] array; private int currentIndex; private boolean isSorting; public BubbleSortAnimation() { setTitle("Bubble Sort Animation"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(WINDOW_WIDTH, WINDOW_HEIGHT); setResizable(false); isSorting = false; currentIndex = ARRAY_SIZE - 1; array = new int[ARRAY_SIZE]; generateRandomArray(); JButton sortButton = new JButton("Sort"); sortButton.addActionListener(e -> { if (!isSorting) { isSorting = true; currentIndex = ARRAY_SIZE - 1; new Thread(this::bubbleSort).start(); } }); JPanel mainPanel = new JPanel(); mainPanel.setLayout(new BorderLayout()); mainPanel.add(sortButton, BorderLayout.NORTH); mainPanel.add(new ArrayPanel(), BorderLayout.CENTER); setContentPane(mainPanel); setVisible(true); } private void generateRandomArray() { Random rand = new Random(); for (int i = 0; i < ARRAY_SIZE; i++) { array[i] = rand.nextInt(ARRAY_SIZE * BAR_HEIGHT_MULTIPLIER) + 1; } } private void bubbleSort() { while (currentIndex > 0) { boolean swapped = false; for (int i = 0; i < currentIndex; i++) { if (array[i] > array[i + 1]) { int temp = array[i]; array[i] = array[i + 1]; array[i + 1] = temp; swapped = true; } try { Thread.sleep(DELAY); } catch (InterruptedException e) { e.printStackTrace(); } } currentIndex--; if (!swapped) { break; } } isSorting = false; } private class ArrayPanel extends JPanel { private static final int PANEL_WIDTH = ARRAY_SIZE * BAR_WIDTH; private static final int PANEL_HEIGHT = WINDOW_HEIGHT - 100; public ArrayPanel() { setSize(PANEL_WIDTH, PANEL_HEIGHT); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); for (int i = 0; i < ARRAY_SIZE; i++) { int x = i * BAR_WIDTH; int y = PANEL_HEIGHT - array[i] / BAR_HEIGHT_MULTIPLIER; g.fillRect(x, y, BAR_WIDTH, array[i] / BAR_HEIGHT_MULTIPLIER); } if (isSorting) { g.setColor(Color.RED); int x = currentIndex * BAR_WIDTH; int y = PANEL_HEIGHT - array[currentIndex] / BAR_HEIGHT_MULTIPLIER; g.drawRect(x, y, BAR_WIDTH, array[currentIndex] / BAR_HEIGHT_MULTIPLIER); } } @Override public Dimension getPreferredSize() { return new Dimension(PANEL_WIDTH, PANEL_HEIGHT); } } public static void main(String[] args) { new BubbleSortAnimation(); } } ``` 这个程序中,我们使用了Java Swing中的JFrame、JPanel和Graphics等组件和类来绘制UI界面和实现动画效果。在JFrame中,我们添加了一个按钮和一个JPanel,用来触发冒泡排序和显示排序过程中的数组状态。在JPanel中,我们使用了paintComponent()方法来实现绘制数组的柱状图,同时也绘制了当前正在处理的元素的状态。 在冒泡排序的实现中,我们使用了一个while循环和一个for循环来进行排序。在每次for循环中,我们比较相邻两个元素的大小,如果需要交换则进行交换,并且调用Thread.sleep()方法来实现动画效果。在每次for循环结束后,我们将当前正在处理的元素的索引减1,并且检查是否已经完成排序,如果没有完成排序则继续下一轮排序。最终,当排序完成后,我们将isSorting标志位设置为false,表示排序已经结束。 当用户点击按钮触发排序时,我们创建一个新线程来执行排序算法,以避免阻塞UI线程。在排序过程中,我们使用isSorting标志位来控制排序的开始和结束,并且将currentIndex变量作为当前正在处理的元素的索引。 运行程序后,点击Sort按钮即可开始冒泡排序的UI动画
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

linwu-hi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值