首页 > 其他分享 >冒泡排序 (Bubble Sort) 详解

冒泡排序 (Bubble Sort) 详解

时间:2024-10-12 19:19:43浏览次数:9  
标签:Sort arr 复杂度 元素 交换 冒泡排序 排序 Bubble

一、概述

冒泡排序(Bubble Sort)是一种基础的排序算法,属于交换排序的一种。它通过重复遍历要排序的数列,比较相邻的元素并交换它们的位置,逐步将最大的(或最小的)元素“冒泡”到数列的末端,从而完成排序。

冒泡排序的工作原理非常直观易懂,尽管它的性能并不算最优,但作为入门级的排序算法,它能帮助我们理解排序的基本思想。

冒泡排序的特点

  • 时间复杂度:最坏和平均情况下,冒泡排序的时间复杂度为 O(n²)。
  • 空间复杂度:冒泡排序是就地排序算法,因此空间复杂度为 O(1)。
  • 稳定性:冒泡排序是一种稳定的排序算法。即相同元素的相对位置不会改变。

应用场景

冒泡排序适合在数据量较小、对算法效率要求不高的场景下使用。例如,学生做算法练习或在理解其他复杂排序算法之前作为过渡学习。由于其低效性,它在实际生产中不常使用。

二、冒泡排序的原理

冒泡排序的核心思想是:两两比较相邻元素,如果它们的顺序错误就交换它们的位置。这样一轮遍历结束后,当前的最大元素就会被交换到数组的最后位置。接下来对剩下的元素重复这一过程,直到所有元素有序。

具体过程如下:

  1. 比较第一个和第二个元素,如果第一个比第二个大,交换这两个元素;
  2. 接着比较第二个和第三个元素,若第二个比第三个大,交换它们;
  3. 如此继续,直到最后一对元素;
  4. 每经过一轮比较,最大的元素就会被放在最后(或者最小的元素放在数组开头,取决于排序方式),不再参与后续的排序。

重复上述过程,直到数组有序为止。

示例

假设我们要对以下数组进行升序排序:

[5, 1, 4, 2, 8]

冒泡排序的执行过程如下:

  • 第 1 轮:
  • 比较 51,由于 5 > 1,交换,得到 [1, 5, 4, 2, 8]
  • 比较 54,由于 5 > 4,交换,得到 [1, 4, 5, 2, 8]
  • 比较 52,由于 5 > 2,交换,得到 [1, 4, 2, 5, 8]
  • 比较 58,由于 5 < 8,无需交换,数组仍为 [1, 4, 2, 5, 8]

第 1 轮结束时,最大的元素 8 已经被放置在最后。

  • 第 2 轮:
  • 比较 14,由于 1 < 4,无需交换
  • 比较 42,由于 4 > 2,交换,得到 [1, 2, 4, 5, 8]
  • 比较 45,由于 4 < 5,无需交换

此时,数组的最后两个元素已经排好序。

  • 第 3 轮:
  • 比较 12,无需交换
  • 比较 24,无需交换

所有元素都有序,排序完成。

最终结果为 [1, 2, 4, 5, 8]

三、冒泡排序的算法实现

下面是用 Python 实现的冒泡排序:

def bubble_sort(arr):
    n = len(arr)
    for i in range(n):
        # 设置一个标志位,用于检测是否有元素交换,如果没有交换说明已经有序
        swapped = False
        for j in range(0, 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. 外层循环 for i in range(n):每轮会将当前未排序部分的最大值移动到数组末端,因此随着每轮排序,待排序部分会逐渐减少。
  2. 内层循环 for j in range(0, n - i - 1):每一轮都要从头开始比较相邻的两个元素,直到剩下未排序的元素。
  3. 交换 arr[j], arr[j + 1] = arr[j + 1], arr[j]:如果前一个元素大于后一个元素,则交换它们的位置。
  4. 优化:通过设置 swapped 标志位,如果在某一轮中没有发生任何交换,说明数组已经有序,可以提前终止排序,减少不必要的循环。

示例运行

arr = [5, 1, 4, 2, 8]
sorted_arr = bubble_sort(arr)
print(sorted_arr)

输出结果:

[1, 2, 4, 5, 8]

四、冒泡排序的优化

虽然冒泡排序的基本思想很简单,但它的时间复杂度较高,通常为 O(n²)。对于较大的数据集,这种算法性能较差。为了提高其效率,我们可以做一些优化:

1. 标志位优化

如前面代码中所展示的,通过引入一个 swapped 标志位,来检测每一轮比较过程中是否有元素被交换。如果在某一轮没有元素交换,说明数组已经有序,可以提前结束排序。

2. 改进循环范围

由于每一轮的比较会将当前未排序部分的最大元素“冒泡”到末尾,因此在下一轮排序时,可以减少内层循环的范围,即 n - i - 1,其中 i 是当前外层循环的轮次,代表已经排序好的元素数量。

3. 鸡尾酒排序

鸡尾酒排序(Cocktail Sort)是冒泡排序的一种改进版,它解决了标准冒泡排序中元素移动效率低的问题。鸡尾酒排序每轮排序时,先从左到右执行一次冒泡操作,然后从右到左再执行一次。这种双向排序方式可以更快地将较小的元素移到数组的前端,缩短了排序时间。

鸡尾酒排序的代码实现:

def cocktail_sort(arr):
    n = len(arr)
    swapped = True
    start = 0
    end = n - 1
    while swapped:
        swapped = False
        # 从左到右进行冒泡排序
        for i in range(start, end):
            if arr[i] > arr[i + 1]:
                arr[i], arr[i + 1] = arr[i + 1], arr[i]
                swapped = True
        if not swapped:
            break
        swapped = False
        end -= 1
        # 从右到左进行冒泡排序
        for i in range(end, start, -1):
            if arr[i] < arr[i - 1]:
                arr[i], arr[i - 1] = arr[i - 1], arr[i]
                swapped = True
        start += 1

4. 时间复杂度和空间复杂度

  • 最坏时间复杂度:O(n²),这是当输入数据完全逆序时,冒泡排序需要执行 n(n-1)/2 次比较和交换。
  • 最佳时间复杂度:O(n),当输入数据已经有序时,只需进行 n 次比较即可结束排序。
  • 平均时间复杂度:O(n²),无论输入数据如何分布,冒泡排序在平均情况下都需要 O(n²) 的时间。
  • 空间复杂度:O(1),冒泡排序是就地排序算法,不需要额外的内存空间,只使用了常量级别的辅助空间。

五、总结

冒泡排序作为一种简单的排序算法,虽然性能较差,但它提供了对交换排序思想的直观理解。尽管在处理大型数据时效率不高,但它通过一系列优化可以在特定情况下表现得更好。通过使用标志位、改进循环范围和借助鸡尾酒排序等改进方法,可以有效提升其性能。然而,由于时间复杂度较高,冒泡排序在实际应用中较少使用,更高效的排序算法如快速排序和归并排序通常会是更好的选择。

关键点总结:

  • 冒泡排序通过反复比较

标签:Sort,arr,复杂度,元素,交换,冒泡排序,排序,Bubble
From: https://blog.51cto.com/boss/12231607

相关文章

  • 冒泡排序、插入排序、选择排序、归并排序、快速排序算法(C++实现)
    文章目录一、冒泡排序上浮法冒泡排序(从小到大排序)下浮法冒泡排序(从大到小排序)二、选择排序三、插入排序四、归并排序五、快速排序参考一、冒泡排序冒泡排序应该算是最经典最简单的排序算法,我一开始学习排序算法就是从冒泡排序开始入门的。冒泡排序算法的基本思路:(......
  • java.util.Arrays#sort
    基本数据类型数组/***java.util.Arrays#sort(int[])*publicstaticvoidsort(int[]a){*DualPivotQuicksort.sort(a,0,a.length-1,null,0,0);//DualPivotQuicksort*}*/Obje......
  • java.util.Collections#sort(java.util.List<T>)
    java.util.ArrayList/java.util.LinkedList/***java.util.Collections#sort(java.util.List)*publicstatic<TextendsComparable<?superT>>voidsort(List<T>list){*list.sort(null);*......
  • C代码随笔——冒泡排序
    题目:对一串乱序数字排序并且进行重复元素去重冒泡排序的基本规则:        比较相邻的元素。如果第一个比第二个大(升序排序),就交换它们两个。对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。重复以上的步骤,除了最后已......
  • ABC302G Sort from 1 to 4 [关键性质题]
    Description给定一个长度为\(N\)的序列,其中每个元素都是介于\(1\)和\(4\)之间的整数。可以进行以下操作任意次(可能为零次):选择一对整数\((i,j)\),其中\(1≤i<j≤N\),并交换\(A_i\)和\(A_j\)。输出使序列\(A\)变为非递减序列所需的最小操作次数。Solution对于这......
  • 5.3 C#数组的基本操作与排序(数组赋值、最大最小值、冒泡排序、选择排序、Array类排序)
    文章目录5.3.1C#数组对象的赋值例5-5:通过循环给一维数组赋值例5-6:通过键盘输入给数组赋值5.3.2C#数组对象的输出例5-7:不同类型数组的输出5.3.3C#求数组中的最大(小)元素值例5-8:求数组中的最大值和最小值5.3.4C#数组排序1.使用Array类排序(例5-9)2.冒泡排序(例5-......
  • 信息学奥赛复赛复习13-CSP-J2021-02插入排序-排序稳定性、插入排序、sort排序、结构体
    PDF文档公众号回复关键字:202410061P7910[CSP-J2021]插入排序[题目描述]插入排序是一种非常常见且简单的排序算法。小Z是一名大一的新生,今天H老师刚刚在上课的时候讲了插入排序算法。假设比较两个元素的时间为O(1),则插入排序可以以O(n^2)的时间复杂度完成长度为......
  • python: sort
     table=[['1','Du','GeovinDu','13824350518',92],['2','Rose','Tom','1882458888',38],['3','Lin','bo','......
  • sort函数详解
    sort函数简介其实STL中的sort()并非只是普通的快速排序,除了对普通的快速排序进行优化,它还结合了插入排序和堆排序。根据不同的数量级别以及不同情况,能自动选用合适的排序方法。当数据量较大时采用快速排序,分段递归。一旦分段后的数据量小于某个阀值,为避免递归调用带来过大的额外......
  • topo sort
    P1038神经网络,拓扑排序板子题include<bits/stdc++.h>usingnamespacestd;constintN=1e2+10;structnode{intv,w;};vectorg[N];queueq;intn,m;boolflag=true;intc[N],in[N],out[N],vis[N];voidtopsort(){while(!q.empty()){intu=q.front();q.pop();......