冒泡排序全攻略:概念、原理、复杂度与代码详解
一、冒泡排序的基本概念
冒泡排序(Bubble Sort)是一种简单的排序算法。它重复地走访要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。
这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端(升序排列的情况),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样。
二、冒泡排序的原理
- 比较相邻元素
- 假设我们有一个包含n个元素的数组
arr
,首先从数组的第一个元素arr[0]
开始,比较arr[0]
和arr[1]
。如果arr[0]>arr[1]
(在升序排列的情况下),则交换这两个元素的位置。 - 接着比较
arr[1]
和arr[2]
,以此类推,直到比较完arr[n - 2]
和arr[n - 1]
。这样经过一轮比较后,最大的元素就会“浮”到数组的最后一个位置。
- 假设我们有一个包含n个元素的数组
- 多轮比较
- 第一轮比较结束后,最大的元素已经在正确的位置(数组的末尾)。然后我们对剩下的
n - 1
个元素进行同样的操作,即从arr[0]
开始比较相邻元素,直到arr[n - 3]
和arr[n - 2]
比较完,这一轮会把第二大的元素放到数组的倒数第二个位置。 - 重复这个过程,总共需要进行
n - 1
轮比较,每一轮比较的元素个数会逐渐减少。
- 第一轮比较结束后,最大的元素已经在正确的位置(数组的末尾)。然后我们对剩下的
例如,对于数组[5, 4, 3, 2, 1]
:
- 第一轮比较:
- 比较
5
和4
,交换位置得到[4, 5, 3, 2, 1]
。 - 比较
5
和3
,交换位置得到[4, 3, 5, 2, 1]
。 - 比较
5
和2
,交换位置得到[4, 3, 2, 5, 1]
。 - 比较
5
和1
,交换位置得到[4, 3, 2, 1, 5]
。此时第一轮结束,最大的元素5
已经在正确位置。
- 比较
- 第二轮比较:
- 比较
4
和3
,交换位置得到[3, 4, 2, 1, 5]
。 - 比较
4
和2
,交换位置得到[3, 2, 4, 1, 5]
。 - 比较
4
和1
,交换位置得到[3, 2, 1, 4, 5]
。第二轮结束,第二大的元素4
在正确位置。
- 比较
- 依此类推,直到整个数组排序完成。
三、时间复杂度和空间复杂度
- 时间复杂度
- 最坏情况:当输入的数组是完全逆序的时候,例如
[n, n - 1, n - 2,..., 1]
。对于长度为n的数组,第一轮需要比较n - 1
次,第二轮需要比较n - 2
次,以此类推,总共需要比较的次数是((n-1)+(n - 2)+...+1=\frac{n(n - 1)}{2})。所以最坏情况下时间复杂度是(O(n^{2}))。 - 最好情况:当输入的数组已经是有序的,例如
[1, 2, 3,..., n]
,只需要进行一轮比较,比较次数为n - 1
次,时间复杂度是(O(n))。 - 平均情况:时间复杂度也是(O(n^{2})),因为在平均情况下,元素的无序程度使得比较次数依然会接近最坏情况。
- 最坏情况:当输入的数组是完全逆序的时候,例如
- 空间复杂度
- 冒泡排序是一种原地排序算法,它只需要少量的额外空间来交换元素,空间复杂度是(O(1)),因为它在排序过程中只需要使用几个临时变量来交换元素的位置,不需要额外的存储空间来存储整个数组的副本等。
四、代码实现(以Python为例)
def bubble_sort(arr):
n = len(arr)
for i in range(n):
for j in range(0, n - i - 1):
if arr[j] > arr[j + 1]:
# 交换元素位置
arr[j], arr[j + 1] = arr[j + 1], arr[j]
return arr
在这段代码中:
- 外层循环
for i in range(n)
控制排序的轮数,总共需要n - 1
轮。 - 内层循环
for j in range(0, n - i - 1)
控制每一轮中比较的次数,每一轮比较的元素个数会随着轮数的增加而减少。 - 如果
arr[j]>arr[j + 1]
,则通过arr[j], arr[j + 1]=arr[j + 1], arr[j]
交换这两个元素的位置。
五、冒泡排序的优缺点
- 优点
- 实现简单:代码逻辑比较直接,容易理解和编写。对于初学者来说,是学习排序算法的一个很好的入门示例。
- 稳定性好:在排序过程中,如果两个元素相等,它们的相对位置不会改变。例如,对于数组
[3, 2, 2, 1]
,排序后两个2
的相对位置不会改变。
- 缺点
- 时间效率低:当数据量较大时,由于时间复杂度是(O(n^{2})),会导致排序速度很慢。在实际应用中,对于大规模数据的排序,一般不会使用冒泡排序,而是会选择更高效的排序算法,如快速排序、归并排序等。