<C++>冒泡排序、归并排序详解 时间复杂度 与应用
目录
一、冒泡排序(Bubble Sort)
1. 原理
2. 代码实现
3. 复杂度分析
4. 应用场景
二、归并排序(Merge Sort)
1. 原理
2. 代码实现
3. 复杂度分析
4. 应用场景
三、对比与选择
四、测试示例
例题应用
四、如何选择?
三、对比总结
一、冒泡排序(Bubble Sort)
1. 原理
冒泡排序通过 重复遍历数组,比较相邻元素,若顺序错误则交换它们。每一轮遍历将未排序部分的最大元素“冒泡”到正确位置。优化后可提前终止排序(若某次遍历无交换,说明已有序)。
2. 代码实现
#include <iostream>
#include <vector>void bubbleSort(std::vector<int>& arr) {int n = arr.size();bool swapped;for (int i = 0; i < n-1; i++) {swapped = false;for (int j = 0; j < n-i-1; j++) {if (arr[j] > arr[j+1]) {std::swap(arr[j], arr[j+1]);swapped = true;}}if (!swapped) break; // 提前终止优化}
}
3. 复杂度分析
-
时间复杂度:
-
最好情况(已有序):O(n)
-
平均和最坏情况:O(n²)
-
-
空间复杂度:O(1),原地排序。
4. 应用场景
-
小规模数据排序。
-
检测数组是否有序(优化后)。
-
教学用途,理解排序基础逻辑。
--------------------------------------------------------------------------------------------------------------------------
二、归并排序(Merge Sort)
1. 原理
归并排序采用 分治策略:
-
分割:递归将数组分成两半,直到子数组长度为1。
-
合并:将两个有序子数组合并为一个有序数组,需额外空间。
2. 代码实现
#include <iostream>
#include <vector>// 合并两个有序子数组
void merge(std::vector<int>& arr, int left, int mid, int right) {std::vector<int> temp(right - left + 1);int i = left, j = mid + 1, k = 0;while (i <= mid && j <= right) {if (arr[i] <= arr[j]) temp[k++] = arr[i++];else temp[k++] = arr[j++];}while (i <= mid) temp[k++] = arr[i++];while (j <= right) temp[k++] = arr[j++];for (int p = 0; p < k; p++) {arr[left + p] = temp[p];}
}// 递归分割与合并
void mergeSort(std::vector<int>& arr, int left, int right) {if (left >= right) return;int mid = left + (right - left) / 2;mergeSort(arr, left, mid);mergeSort(arr, mid + 1, right);merge(arr, left, mid, right);
}// 包装函数
void mergeSort(std::vector<int>& arr) {mergeSort(arr, 0, arr.size() - 1);
}
3. 复杂度分析
-
时间复杂度:所有情况均为 O(n log n)。
-
空间复杂度:O(n),合并时需要临时数组。
4. 应用场景
-
大规模数据排序,尤其内存充足时。
-
需要稳定排序的场景(如数据库排序)。
-
外部排序(处理超出内存的数据)。
三、对比与选择
特性 | 冒泡排序 | 归并排序 |
---|---|---|
时间复杂度 | O(n²)(平均/最坏) | O(n log n) |
空间复杂度 | O(1) | O(n) |
稳定性 | 稳定 | 稳定 |
适用数据规模 | 小规模 | 大规模 |
额外空间 | 无 | 需要 |
实现难度 | 简单 | 中等 |
选择建议:
-
冒泡排序:数据量小或已接近有序。
-
归并排序:数据量大且需要稳定性,或内存不受限。
四、测试示例
int main() {std::vector<int> arr1 = {64, 34, 25, 12, 22, 11, 90};bubbleSort(arr1);std::cout << "Bubble Sort Result: ";for (int num : arr1) std::cout << num << " ";std::cout << "\n";std::vector<int> arr2 = {38, 27, 43, 3, 9, 82, 10};mergeSort(arr2);std::cout << "Merge Sort Result: ";for (int num : arr2) std::cout << num << " ";std::cout << "\n";return 0;
}
输出:
Bubble Sort Result: 11 12 22 25 34 64 90 Merge Sort Result: 3 9 10 27 38 43 82
例题应用
-
LeetCode 148. 排序链表
-
题目要求:在 O(n log n) 时间内对链表排序。
-
解法:归并排序(适合链表的递归分治)。
cpp
-
-
ListNode* mergeSort(ListNode* head) {if (!head || !head->next) return head;ListNode* slow = head, *fast = head->next;while (fast && fast->next) {slow = slow->next;fast = fast->next->next;}ListNode* mid = slow->next;slow->next = nullptr;return merge(mergeSort(head), mergeSort(mid)); }
-
逆序对问题(LeetCode 493. 翻转对)
-
题目要求:统计数组中满足
nums[i] > 2 * nums[j]
的逆序对。 -
解法:归并排序过程中统计逆序对。
cpp
-
int count = 0;
void mergeAndCount(vector<int>& nums, int left, int mid, int right) {// ...合并逻辑...// 在合并前统计逆序对int i = left, j = mid + 1;while (i <= mid && j <= right) {if ((long)nums[i] > 2 * (long)nums[j]) {count += mid - i + 1;j++;} else {i++;}}
}
四、如何选择?
-
数据规模小 → 冒泡排序(或插入排序)。
-
数据规模大 → 归并排序(或快速排序)。
-
需要稳定性 → 归并排序。
-
内存有限 → 冒泡排序(原地排序)。
三、对比总结
特性 | 冒泡排序 | 归并排序 |
---|---|---|
时间复杂度 | O(n²)(最坏/平均) | O(n log n)(所有情况) |
空间复杂度 | O(1)(原地排序) | O(n)(需额外空间) |
稳定性 | 稳定 | 稳定 |
适用场景 | 小数据、部分有序数组 | 大规模数据、外部排序 |