排序算法可视化 - 冒泡、插入、选择排序详解

算法可视化演示

20
300ms
就绪
冒泡排序

比较次数

0

交换次数

0

执行时间

0ms

当前步骤

0

冒泡排序

冒泡排序是一种简单的排序算法,它重复地走访过要排序的数列,一次比较两个相邻的元素,如果它们的顺序错误就把它们交换过来。

这个算法的名字由来是因为越小的元素会经由交换慢慢"浮"到数列的顶端,就像水中的气泡一样向上冒。

工作原理:

  1. 从数组的第一个元素开始,比较相邻的两个元素
  2. 如果第一个比第二个大,则交换它们的位置
  3. 对每一对相邻元素重复同样的工作,从开始第一对到结尾的最后一对
  4. 完成一轮后,最大的元素会"浮"到数组的末尾
  5. 针对所有的元素重复以上的步骤,除了最后已经排好序的元素
  6. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较

时间复杂度

最佳: O(n)

平均: O(n²)

最坏: O(n²)

空间复杂度

O(1) - 原地排序

稳定性

稳定排序

冒泡排序代码实现 (Python)

def bubble_sort(arr):
    n = len(arr)
    # 外层循环控制需要进行多少轮比较
    for i in range(n - 1):
        swapped = False
        # 内层循环进行相邻元素的比较和交换
        # 每完成一轮,最大的元素已经到位,不需要再比较
        for j in range(n - i - 1):
            # 比较相邻元素
            if arr[j] > arr[j + 1]:
                # 交换元素
                arr[j], arr[j + 1] = arr[j + 1], arr[j]
                swapped = True
        # 如果在这一轮中没有发生交换,说明数组已经有序
        if not swapped:
            break
    return arr

插入排序

插入排序是一种简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

插入排序的思想类似于我们玩扑克牌时,将每张牌插入到已有序的牌中的适当位置。

工作原理:

  1. 从第一个元素开始,该元素可以认为已经被排序
  2. 取出下一个元素,在已经排序的元素序列中从后向前扫描
  3. 如果该元素(已排序)大于新元素,将该元素移到下一位置
  4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
  5. 将新元素插入到该位置后
  6. 重复步骤2~5,直到所有元素均排序完毕

时间复杂度

最佳: O(n)

平均: O(n²)

最坏: O(n²)

空间复杂度

O(1) - 原地排序

稳定性

稳定排序

插入排序代码实现 (Python)

def insertion_sort(arr):
    # 从第二个元素开始,第一个元素默认已排序
    for i in range(1, len(arr)):
        # 保存当前要插入的元素
        key = arr[i]
        # 从已排序序列的末尾开始比较
        j = i - 1
        
        # 将大于key的元素向后移动一位
        while j >= 0 and key < arr[j]:
            arr[j + 1] = arr[j]
            j -= 1
        
        # 将key插入到正确的位置
        arr[j + 1] = key
    
    return arr

选择排序

选择排序是一种简单直观的排序算法,它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。

以此类推,直到全部待排序的数据元素排完。选择排序是不稳定的排序方法。

工作原理:

  1. 初始状态:整个数组为待排序区域,已排序区域为空
  2. 从待排序区域中找到最小(或最大)的元素
  3. 将找到的最小(或最大)元素与待排序区域的第一个元素交换位置
  4. 此时已排序区域增加一个元素,待排序区域减少一个元素
  5. 重复步骤2~4,直到待排序区域为空

时间复杂度

最佳: O(n²)

平均: O(n²)

最坏: O(n²)

空间复杂度

O(1) - 原地排序

稳定性

不稳定排序

选择排序代码实现 (Python)

def selection_sort(arr):
    # 外层循环控制已排序区域的末尾
    for i in range(len(arr) - 1):
        # 假设当前元素是最小值
        min_index = i
        
        # 在未排序区域中寻找最小值
        for j in range(i + 1, len(arr)):
            if arr[j] < arr[min_index]:
                min_index = j  # 更新最小值的索引
        
        # 将找到的最小值与未排序区域的第一个元素交换
        arr[i], arr[min_index] = arr[min_index], arr[i]
    
    return arr

算法比较

特性 冒泡排序 插入排序 选择排序
时间复杂度(最佳) O(n) O(n) O(n²)
时间复杂度(平均) O(n²) O(n²) O(n²)
时间复杂度(最坏) O(n²) O(n²) O(n²)
空间复杂度 O(1) O(1) O(1)
稳定性 稳定 稳定 不稳定
交换次数 较多(O(n²)) 较少(O(n)) 最少(O(n))
比较次数 O(n²) O(n²) O(n²)
适用场景 数据量小且接近有序 数据量小且部分有序 数据量小,对交换成本敏感

如何选择合适的排序算法?

  • 当数据基本有序时:优先选择冒泡排序或插入排序,它们在这种情况下性能较好,接近O(n)
  • 当数据规模较小时:三种算法均可,但插入排序通常表现更好
  • 当交换操作成本较高时:选择排序更有优势,因为它的交换次数最少
  • 当需要稳定排序时:避免使用选择排序,优先考虑冒泡排序或插入排序
  • 当数据规模较大时:这三种算法都不适合,应考虑快速排序、归并排序等更高效的算法
代码已复制到剪贴板