11.3 Bubble sort¶
Bubble sort achieves sorting by continuously comparing and swapping adjacent elements. This process resembles bubbles rising from the bottom to the top, hence the name bubble sort.
As shown in Figure 11-4, the bubbling process can be simulated using element swap operations: starting from the leftmost end of the array and moving right, sequentially compare the size of adjacent elements. If "left element > right element," then swap them. After the traversal, the largest element will be moved to the far right end of the array.
Figure 11-4 Simulating bubble process using element swap
11.3.1 Algorithm process¶
Assuming the length of the array is \(n\), the steps of bubble sort are shown in Figure 11-5.
- First, perform a "bubble" on \(n\) elements, swapping the largest element to its correct position.
- Next, perform a "bubble" on the remaining \(n - 1\) elements, swapping the second largest element to its correct position.
- Similarly, after \(n - 1\) rounds of "bubbling," the top \(n - 1\) largest elements will be swapped to their correct positions.
- The only remaining element is necessarily the smallest and does not require sorting, thus the array sorting is complete.
Figure 11-5 Bubble sort process
Example code is as follows:
/* 冒泡排序 */
void bubbleSort(vector<int> &nums) {
// 外循环:未排序区间为 [0, i]
for (int i = nums.size() - 1; i > 0; i--) {
// 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端
for (int j = 0; j < i; j++) {
if (nums[j] > nums[j + 1]) {
// 交换 nums[j] 与 nums[j + 1]
// 这里使用了 std::swap() 函数
swap(nums[j], nums[j + 1]);
}
}
}
}
/* 冒泡排序 */
void bubbleSort(int[] nums) {
// 外循环:未排序区间为 [0, i]
for (int i = nums.length - 1; i > 0; i--) {
// 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端
for (int j = 0; j < i; j++) {
if (nums[j] > nums[j + 1]) {
// 交换 nums[j] 与 nums[j + 1]
int tmp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = tmp;
}
}
}
}
/* 冒泡排序 */
void BubbleSort(int[] nums) {
// 外循环:未排序区间为 [0, i]
for (int i = nums.Length - 1; i > 0; i--) {
// 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端
for (int j = 0; j < i; j++) {
if (nums[j] > nums[j + 1]) {
// 交换 nums[j] 与 nums[j + 1]
(nums[j + 1], nums[j]) = (nums[j], nums[j + 1]);
}
}
}
}
/* 冒泡排序 */
function bubbleSort(nums) {
// 外循环:未排序区间为 [0, i]
for (let i = nums.length - 1; i > 0; i--) {
// 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端
for (let j = 0; j < i; j++) {
if (nums[j] > nums[j + 1]) {
// 交换 nums[j] 与 nums[j + 1]
let tmp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = tmp;
}
}
}
}
/* 冒泡排序 */
function bubbleSort(nums: number[]): void {
// 外循环:未排序区间为 [0, i]
for (let i = nums.length - 1; i > 0; i--) {
// 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端
for (let j = 0; j < i; j++) {
if (nums[j] > nums[j + 1]) {
// 交换 nums[j] 与 nums[j + 1]
let tmp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = tmp;
}
}
}
}
/* 冒泡排序 */
void bubbleSort(List<int> nums) {
// 外循环:未排序区间为 [0, i]
for (int i = nums.length - 1; i > 0; i--) {
// 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端
for (int j = 0; j < i; j++) {
if (nums[j] > nums[j + 1]) {
// 交换 nums[j] 与 nums[j + 1]
int tmp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = tmp;
}
}
}
}
// 冒泡排序
fn bubbleSort(nums: []i32) void {
// 外循环:未排序区间为 [0, i]
var i: usize = nums.len - 1;
while (i > 0) : (i -= 1) {
var j: usize = 0;
// 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端
while (j < i) : (j += 1) {
if (nums[j] > nums[j + 1]) {
// 交换 nums[j] 与 nums[j + 1]
var tmp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = tmp;
}
}
}
}
Code Visualization
11.3.2 Efficiency optimization¶
We find that if no swaps are performed in a round of "bubbling," the array is already sorted, and we can return the result immediately. Thus, we can add a flag flag to monitor this situation and return immediately when it occurs.
Even after optimization, the worst-case time complexity and average time complexity of bubble sort remain at \(O(n^2)\); however, when the input array is completely ordered, it can achieve the best time complexity of \(O(n)\).
def bubble_sort_with_flag(nums: list[int]):
"""冒泡排序(标志优化)"""
n = len(nums)
# 外循环:未排序区间为 [0, i]
for i in range(n - 1, 0, -1):
flag = False # 初始化标志位
# 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端
for j in range(i):
if nums[j] > nums[j + 1]:
# 交换 nums[j] 与 nums[j + 1]
nums[j], nums[j + 1] = nums[j + 1], nums[j]
flag = True # 记录交换元素
if not flag:
break # 此轮“冒泡”未交换任何元素,直接跳出
/* 冒泡排序(标志优化)*/
void bubbleSortWithFlag(vector<int> &nums) {
// 外循环:未排序区间为 [0, i]
for (int i = nums.size() - 1; i > 0; i--) {
bool flag = false; // 初始化标志位
// 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端
for (int j = 0; j < i; j++) {
if (nums[j] > nums[j + 1]) {
// 交换 nums[j] 与 nums[j + 1]
// 这里使用了 std::swap() 函数
swap(nums[j], nums[j + 1]);
flag = true; // 记录交换元素
}
}
if (!flag)
break; // 此轮“冒泡”未交换任何元素,直接跳出
}
}
/* 冒泡排序(标志优化) */
void bubbleSortWithFlag(int[] nums) {
// 外循环:未排序区间为 [0, i]
for (int i = nums.length - 1; i > 0; i--) {
boolean flag = false; // 初始化标志位
// 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端
for (int j = 0; j < i; j++) {
if (nums[j] > nums[j + 1]) {
// 交换 nums[j] 与 nums[j + 1]
int tmp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = tmp;
flag = true; // 记录交换元素
}
}
if (!flag)
break; // 此轮“冒泡”未交换任何元素,直接跳出
}
}
/* 冒泡排序(标志优化)*/
void BubbleSortWithFlag(int[] nums) {
// 外循环:未排序区间为 [0, i]
for (int i = nums.Length - 1; i > 0; i--) {
bool flag = false; // 初始化标志位
// 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端
for (int j = 0; j < i; j++) {
if (nums[j] > nums[j + 1]) {
// 交换 nums[j] 与 nums[j + 1]
(nums[j + 1], nums[j]) = (nums[j], nums[j + 1]);
flag = true; // 记录交换元素
}
}
if (!flag) break; // 此轮“冒泡”未交换任何元素,直接跳出
}
}
/* 冒泡排序(标志优化)*/
func bubbleSortWithFlag(nums []int) {
// 外循环:未排序区间为 [0, i]
for i := len(nums) - 1; i > 0; i-- {
flag := false // 初始化标志位
// 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端
for j := 0; j < i; j++ {
if nums[j] > nums[j+1] {
// 交换 nums[j] 与 nums[j + 1]
nums[j], nums[j+1] = nums[j+1], nums[j]
flag = true // 记录交换元素
}
}
if flag == false { // 此轮“冒泡”未交换任何元素,直接跳出
break
}
}
}
/* 冒泡排序(标志优化)*/
func bubbleSortWithFlag(nums: inout [Int]) {
// 外循环:未排序区间为 [0, i]
for i in nums.indices.dropFirst().reversed() {
var flag = false // 初始化标志位
for j in 0 ..< i {
if nums[j] > nums[j + 1] {
// 交换 nums[j] 与 nums[j + 1]
nums.swapAt(j, j + 1)
flag = true // 记录交换元素
}
}
if !flag { // 此轮“冒泡”未交换任何元素,直接跳出
break
}
}
}
/* 冒泡排序(标志优化)*/
function bubbleSortWithFlag(nums) {
// 外循环:未排序区间为 [0, i]
for (let i = nums.length - 1; i > 0; i--) {
let flag = false; // 初始化标志位
// 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端
for (let j = 0; j < i; j++) {
if (nums[j] > nums[j + 1]) {
// 交换 nums[j] 与 nums[j + 1]
let tmp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = tmp;
flag = true; // 记录交换元素
}
}
if (!flag) break; // 此轮“冒泡”未交换任何元素,直接跳出
}
}
/* 冒泡排序(标志优化)*/
function bubbleSortWithFlag(nums: number[]): void {
// 外循环:未排序区间为 [0, i]
for (let i = nums.length - 1; i > 0; i--) {
let flag = false; // 初始化标志位
// 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端
for (let j = 0; j < i; j++) {
if (nums[j] > nums[j + 1]) {
// 交换 nums[j] 与 nums[j + 1]
let tmp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = tmp;
flag = true; // 记录交换元素
}
}
if (!flag) break; // 此轮“冒泡”未交换任何元素,直接跳出
}
}
/* 冒泡排序(标志优化)*/
void bubbleSortWithFlag(List<int> nums) {
// 外循环:未排序区间为 [0, i]
for (int i = nums.length - 1; i > 0; i--) {
bool flag = false; // 初始化标志位
// 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端
for (int j = 0; j < i; j++) {
if (nums[j] > nums[j + 1]) {
// 交换 nums[j] 与 nums[j + 1]
int tmp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = tmp;
flag = true; // 记录交换元素
}
}
if (!flag) break; // 此轮“冒泡”未交换任何元素,直接跳出
}
}
/* 冒泡排序(标志优化) */
fn bubble_sort_with_flag(nums: &mut [i32]) {
// 外循环:未排序区间为 [0, i]
for i in (1..nums.len()).rev() {
let mut flag = false; // 初始化标志位
// 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端
for j in 0..i {
if nums[j] > nums[j + 1] {
// 交换 nums[j] 与 nums[j + 1]
let tmp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = tmp;
flag = true; // 记录交换元素
}
}
if !flag {
break; // 此轮“冒泡”未交换任何元素,直接跳出
};
}
}
/* 冒泡排序(标志优化)*/
void bubbleSortWithFlag(int nums[], int size) {
// 外循环:未排序区间为 [0, i]
for (int i = size - 1; i > 0; i--) {
bool flag = false;
// 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端
for (int j = 0; j < i; j++) {
if (nums[j] > nums[j + 1]) {
int temp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = temp;
flag = true;
}
}
if (!flag)
break;
}
}
/* 冒泡排序(标志优化) */
fun bubbleSortWithFlag(nums: IntArray) {
// 外循环:未排序区间为 [0, i]
for (i in nums.size - 1 downTo 1) {
var flag = false // 初始化标志位
// 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端
for (j in 0..<i) {
if (nums[j] > nums[j + 1]) {
// 交换 nums[j] 与 nums[j + 1]
val temp = nums[j]
nums[j] = nums[j + 1]
nums[j + 1] = temp
flag = true // 记录交换元素
}
}
if (!flag) break // 此轮“冒泡”未交换任何元素,直接跳出
}
}
// 冒泡排序(标志优化)
fn bubbleSortWithFlag(nums: []i32) void {
// 外循环:未排序区间为 [0, i]
var i: usize = nums.len - 1;
while (i > 0) : (i -= 1) {
var flag = false; // 初始化标志位
var j: usize = 0;
// 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端
while (j < i) : (j += 1) {
if (nums[j] > nums[j + 1]) {
// 交换 nums[j] 与 nums[j + 1]
var tmp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = tmp;
flag = true;
}
}
if (!flag) break; // 此轮“冒泡”未交换任何元素,直接跳出
}
}
Code Visualization
11.3.3 Algorithm characteristics¶
- Time complexity of \(O(n^2)\), adaptive sorting: The length of the array traversed in each round of "bubbling" decreases sequentially from \(n - 1\), \(n - 2\), \(\dots\), \(2\), \(1\), totaling \((n - 1) n / 2\). With the introduction of
flagoptimization, the best time complexity can reach \(O(n)\). - Space complexity of \(O(1)\), in-place sorting: Only a constant amount of extra space is used by pointers \(i\) and \(j\).
- Stable sorting: As equal elements are not swapped during the "bubbling".







