当前位置: 首页 > news >正文

排序---冒泡排序(Bubble Sort)

一、算法核心概念

冒泡排序是一种简单的交换排序算法,其核心思想是:通过重复遍历待排序数组,每次比较相邻的两个元素,若它们的顺序错误(如升序排序中前一个元素大于后一个),则交换它们的位置。经过多轮遍历后,较大的元素会像“气泡”一样逐渐“上浮”到数组的末尾,最终使整个数组有序。

二、基本工作原理

升序排序为例,冒泡排序的工作流程可概括为:

  1. 初始状态:整个数组为“未排序区间”(需排序的元素范围);
  2. 每轮遍历:从数组头部开始,依次比较相邻元素(arr[j]arr[j+1]),若arr[j] > arr[j+1],则交换两者位置;
  3. 范围收缩:每轮遍历结束后,当前未排序区间中最大的元素会“浮”到区间的末尾,因此下一轮的未排序区间可缩小1个元素(无需再检查已“浮”到末尾的元素);
  4. 终止条件:当某轮遍历中没有发生任何元素交换时,说明数组已完全有序,排序结束。
三、步骤演示(实例解析)

以数组[5, 3, 8, 4, 2]为例,演示升序冒泡排序的过程:

轮次未排序区间遍历中的比较与交换本轮结束后数组是否发生交换
1[0,4](全数组)比较5&3→交换→[3,5,8,4,2];
比较5&8→不交换;
比较8&4→交换→[3,5,4,8,2];
比较8&2→交换→[3,5,4,2,8]
[3,5,4,2,8]
2[0,3](前4个元素)比较3&5→不交换;
比较5&4→交换→[3,4,5,2,8];
比较5&2→交换→[3,4,2,5,8]
[3,4,2,5,8]
3[0,2](前3个元素)比较3&4→不交换;
比较4&2→交换→[3,2,4,5,8]
[3,2,4,5,8]
4[0,1](前2个元素)比较3&2→交换→[2,3,4,5,8][2,3,4,5,8]
5[0,0](仅第1个元素)无相邻元素可比较[2,3,4,5,8]否(排序结束)
四、时间复杂度与空间复杂度
  • 时间复杂度

    • 最坏情况:数组完全逆序,需执行n-1轮遍历,每轮比较n-i次(i为轮次),总操作次数为n+(n-1)+...+1 = n(n-1)/2,故为O(n²)
    • 最好情况:数组已完全有序,若添加“交换标志”优化,仅需1轮遍历(n-1次比较)即可判断有序,故为O(n)
    • 平均情况:O(n²)(适用于随机无序数组)。
  • 空间复杂度
    仅需常数个临时变量(用于交换元素和记录标志),故为O(1)(原地排序)。

五、稳定性分析

冒泡排序是稳定的排序算法

  • 稳定性定义:若数组中存在相等元素,排序后它们的相对顺序与原数组一致,则算法稳定。
  • 原因:冒泡排序仅在相邻元素严格逆序(如arr[j] > arr[j+1])时才交换,若arr[j] == arr[j+1],不会触发交换,因此相等元素的相对顺序保持不变。
六、优化策略

基础版冒泡排序在数组已部分有序时仍会执行不必要的遍历,可通过以下优化提升效率:

1. 交换标志优化(核心优化)

添加一个布尔变量(如swapped),记录每轮是否发生交换。若某轮未发生交换,说明数组已有序,可直接终止排序。

2. 记录最后交换位置(进阶优化)

每轮遍历中,记录最后一次发生交换的位置lastSwapIndex。下一轮遍历的终点可设为lastSwapIndex(因为该位置之后的元素已有序),减少无效比较。

七、C++实现代码
1. 基础版实现
#include <iostream>
#include <vector>
using namespace std;// 基础版冒泡排序(升序)
void bubbleSortBasic(vector<int>& arr) {int n = arr.size();// 外层循环:控制轮次(最多n-1轮)for (int i = 0; i < n - 1; ++i) {// 内层循环:遍历未排序区间[0, n-1-i]for (int j = 0; j < n - 1 - i; ++j) {if (arr[j] > arr[j + 1]) {swap(arr[j], arr[j + 1]); // 交换逆序元素}}}
}int main() {vector<int> arr = {5, 3, 8, 4, 2};bubbleSortBasic(arr);for (int num : arr) {cout << num << " "; // 输出:2 3 4 5 8}return 0;
}
2. 优化版实现(交换标志+最后交换位置)
#include <iostream>
#include <vector>
using namespace std;// 优化版冒泡排序(升序)
void bubbleSortOptimized(vector<int>& arr) {int n = arr.size();int lastSwapIndex = 0; // 记录最后一次交换的位置int border = n - 1;    // 当前未排序区间的右边界(初始为数组末尾)for (int i = 0; i < n - 1; ++i) {bool swapped = false; // 标志位:本轮是否发生交换// 内层循环仅遍历到border(减少无效比较)for (int j = 0; j < border; ++j) {if (arr[j] > arr[j + 1]) {swap(arr[j], arr[j + 1]);swapped = true;lastSwapIndex = j; // 更新最后交换位置}}border = lastSwapIndex; // 收缩未排序区间右边界if (!swapped) break;    // 未交换,数组已有序,提前终止}
}int main() {vector<int> arr = {5, 3, 8, 4, 2};bubbleSortOptimized(arr);for (int num : arr) {cout << num << " "; // 输出:2 3 4 5 8}return 0;
}
八、适用场景与局限性
适用场景:
  1. 小规模数据排序:数据量较小时(如n < 100),冒泡排序实现简单,性能可接受;
  2. 几乎有序的数据:若数组已接近有序(仅少数元素逆序),优化后的冒泡排序可快速完成排序(接近O(n)复杂度);
  3. 教学场景:算法逻辑直观,易于理解,适合作为入门排序算法讲解。
局限性:
  1. 大规模数据效率低:时间复杂度为O(n²),对于n > 1000的数组,排序速度远低于O(nlogn)级算法(如快速排序、归并排序);
  2. 交换操作频繁:每轮可能发生多次相邻元素交换,实际运行时间比同复杂度的选择排序更长(选择排序每轮仅1次交换)。

冒泡排序是一种直观、简单的排序算法,核心通过“相邻元素比较交换”使大元素逐步上浮。尽管其时间复杂度较高(O(n²)),但在小规模或近乎有序的数据场景中仍有应用价值。通过“交换标志”和“收缩边界”优化,可显著提升其在部分有序数据上的性能。


文章转载自:

http://qaUvwnoS.rgmLs.cn
http://bOBEVbkS.rgmLs.cn
http://LqzDrPnq.rgmLs.cn
http://FqpcyGMP.rgmLs.cn
http://XlytRxQM.rgmLs.cn
http://1SbK1xgF.rgmLs.cn
http://77kRVVER.rgmLs.cn
http://mq9qpQ1k.rgmLs.cn
http://mY8xCIGg.rgmLs.cn
http://FACZxBlr.rgmLs.cn
http://YC1BRqKe.rgmLs.cn
http://ECmjipBl.rgmLs.cn
http://c582Ln5Y.rgmLs.cn
http://VKhDtIQt.rgmLs.cn
http://CjDkfv0a.rgmLs.cn
http://FHqv6XIU.rgmLs.cn
http://9tR9BlFk.rgmLs.cn
http://Nh41bxJo.rgmLs.cn
http://z9BGaCpe.rgmLs.cn
http://Wis1AhRM.rgmLs.cn
http://EwoZOw3L.rgmLs.cn
http://ze3VMKKR.rgmLs.cn
http://ZCwo9eLj.rgmLs.cn
http://ZwcL6VN3.rgmLs.cn
http://nm5TgiwU.rgmLs.cn
http://8OXq4lQE.rgmLs.cn
http://xg5GBhu0.rgmLs.cn
http://y5bBsBiC.rgmLs.cn
http://AG2nocua.rgmLs.cn
http://JBx2UR0v.rgmLs.cn
http://www.dtcms.com/a/372756.html

相关文章:

  • C++/QT day8(9.8)
  • 【Linux网络编程】传输层协议-----UDP协议
  • 医疗连续体机器人模块化控制界面设计与Python库应用研究(上)
  • 分享|构建产教融合的一体化人工智能实验室综合解决方案
  • 从固定 px 到响应式:Vue + Vite 项目响应式改造实战,解决前端不适配的问题
  • java面试:了解MVCC么,详细解释一下
  • ChatGPT 协作调优:把 SQL 查询从 5s 优化到 300ms 的全过程
  • 长春高新需要新叙事
  • Python用PSO优化SVM与RBFN在自动驾驶系统仿真、手写数字分类应用研究
  • android studio JNI 环境配置实现 java 调用 c/c++
  • 安卓非原创--基于Android Studio 实现的新闻App
  • Flutter Android Studio开发实用技巧
  • Android Studio适配butterknife遇到的坑
  • 论文精读(五):面向链接预测的知识图谱表示学习方法综述
  • 使用AI工具一句话生成PPT
  • 《嵌入式硬件(五):IMX6ULL所需的基础》
  • Vue响应式更新 vs React状态更新:两种范式的底层逻辑与实践差异
  • Qt UDP 网络编程详解
  • CUPP针对性字典安全防范
  • 用nasm汇编器汇编不同位数格式的ELF
  • odoo打印pdf速度慢问题
  • 京东商品评论 API(JSON 数据返回)核心解析
  • SpringMVC(二)
  • 开始理解大型语言模型(LLM)所需的数学基础
  • 搭论文大纲逻辑乱易跑题?AI 3 步梳理框架,自动串逻辑链
  • C#SqlSugar的简单使用
  • 【军事类】军舰识别检测数据集:3400+图像,4类,yolo标注
  • 基于若依框架Vue+TS导出PDF文件的方法
  • ArcGIS学习-18 实战-降雨量空间分布插值分析
  • OpenCV 银行卡号识别