十大排序 —— 冒泡排序

news2024/11/17 9:40:58

十大排序 —— 冒泡排序

  • 什么是冒泡排序
      • 基本步骤
      • 特点
  • 优化
  • 冒泡的各项性能
      • 时间复杂度
      • 空间复杂度
      • 稳定性
      • 总结

我们今天来讲一个大家熟悉的老朋友——冒泡排序

什么是冒泡排序

冒泡排序(Bubble Sort)是一种简单的排序算法,因其工作原理像水底下的气泡逐渐上升至水面而得名。它重复地遍历要排序的数列,比较每对相邻元素的值,如果它们的顺序错误(例如在升序排序中前者大于后者),就交换它们的位置。遍历过程会重复进行,直到整个数列变成有序状态,也就是说在某一次遍历中没有发生任何交换,这表明数列已经是有序的。

基本步骤

  1. 比较相邻元素:从数列的第一个元素开始,对每一对相邻元素做比较。
  2. 交换位置:如果第一个元素大于第二个元素(升序排序的情况下),就交换它们的位置。否则,不做交换,继续比较下一对元素。
  3. 重复上述过程:每次遍历都将未排序部分的最大值(升序时)移至末尾。
  4. 终止条件:当整个数列遍历完一遍后,如果没有发生过交换,说明数列已经是有序的,排序结束。

特点

  • 稳定性:冒泡排序是稳定的排序算法,即相等的元素在排序前后相对位置不会改变。
  • 时间复杂度:最好情况下(输入数组已经是排序好的)为O(n),但最坏和平均情况下的时间复杂度均为O(n^2),其中n是数列的长度。
  • 空间复杂度:O(1),因为排序是原地进行的,不需要额外的存储空间。
  • 效率:由于其较高的时间复杂度,冒泡排序在大规模数据集上效率较低,通常用于教学目的或小规模数据排序。

举个例子

#include <iostream>

// 冒泡排序函数
// 参数: a - 指向待排序数组的指针, size - 数组的大小
void Bubble_Sort(int *a, int size) {
    // 外层循环控制遍历的轮数,每轮将剩余未排序部分的最大元素放到末尾
    for(int i = 0; i < size; i++) {
        // 内层循环负责每一轮的具体比较和交换操作
        // 注意:由于每轮外循环后,最大的元素已经被排到了末尾,所以下一轮可以减少一次比较
        for(int j = 0; j < size - i - 1; j++) {
            // 如果当前元素大于下一个元素(这里应是降序排序,若需升序则应改为a[j] > a[j + 1])
            if(a[j] < a[j + 1]) {
                // 交换元素位置
                int temp = a[j+1]; // 临时保存较大值
                a[j+1] = a[j];     // 将较小值移到后面
                a[j] = temp;       // 将较大值移到前面
            }
        }
    }
}

// 打印数组函数
// 参数: a - 指向数组的指针, size - 数组的大小
void Print(int *a, int size) {
    // 遍历数组并打印每个元素
    for(int i = 0; i < size; i++) {
        std::cout << a[i] << " ";
    }
    // 每行打印结束后换行
    std::cout << std::endl;
}

// 程序主入口
int main() {
    // 定义并初始化一个整型数组
    int arr[] = {64, 34, 25, 12, 22, 11, 90};
    // 计算数组的元素数量
    int n = sizeof(arr)/sizeof(arr[0]);

    // 打印原始数组
    Print(arr, n);

    // 调用冒泡排序函数对数组进行排序
    Bubble_Sort(arr, n);

    // 打印排序后的数组
    Print(arr, n);

    return 0; // 程序正常结束
}

在这里插入图片描述
我们画个图:
在这里插入图片描述
当 i = 0时,就是64和面的数字比较:
在这里插入图片描述
发现90比自己大,64和90交换:
在这里插入图片描述
此时下标j到了6,一轮结束的标志就是 j + 1 < size:
在这里插入图片描述
此时开始第二轮,因为我们第一个数比较过了,我们可以从34之后的数开始,比较5个数,之后再来一轮,比较4个数…这就是内循环的写法的原因:
在这里插入图片描述

优化

  • 提前终止:设置一个标志位,用于记录在一次完整的遍历中是否发生了交换,如果没有交换,说明数组已经是有序的,可提前结束排序。
  • 记录最后一次交换的位置:下次遍历只需到该位置,因为之后的元素已经是有序的。

我们这里用提前终止:

#include <iostream>

// 冒泡排序函数,包含提前终止的优化
// 参数: a - 指向待排序数组的指针, size - 数组的大小
void Bubble_Sort(int *a, int size) {
    // 外层循环控制遍历的轮数
    for(int i = 0; i < size; i++) {
        bool swapped = false; // 添加一个标记,用于检查本轮循环中是否有交换发生

        // 内层循环负责具体比较和交换操作
        // 注意:每轮外循环后,最大的元素已经被排到了末尾,所以下一轮可以减少一次比较
        for(int j = 0; j < size - i - 1; j++) {
            // 检查当前元素是否小于下一个元素(这里实现的是降序排序,升序应为a[j] > a[j + 1])
            if(a[j] < a[j + 1]) {
                // 交换元素
                int temp = a[j+1]; // 临时保存较大值
                a[j+1] = a[j];     // 将较小值移到后面
                a[j] = temp;       // 将较大值移到前面
                swapped = true;    // 标记有交换发生
            }
        }

        // 如果在某次遍历中没有发生任何交换,说明数组已经是有序的,可以提前结束排序
        if(!swapped) break;
    }
}

// 打印数组的函数
// 参数: a - 指向数组的指针, size - 数组的元素数量
void Print(int *a, int size) {
    // 遍历数组并打印每个元素
    for(int i = 0; i < size; i++) {
        std::cout << a[i] << " ";
    }
    // 每行打印完毕后换行
    std::cout << std::endl;
}

// 主函数
int main() {
    // 初始化一个整型数组
    int arr[] = {64, 34, 25, 12, 22, 11, 90};
    // 计算数组长度
    int n = sizeof(arr)/sizeof(arr[0]);

    // 打印原始数组
    Print(arr, n);

    // 对数组进行冒泡排序
    Bubble_Sort(arr, n);

    // 打印排序后的数组
    Print(arr, n);

    return 0; // 程序正常退出
}

冒泡的各项性能

冒泡排序(Bubble Sort)作为一种基础的排序算法,其主要性能指标包括时间复杂度、空间复杂度和稳定性。下面是这些性能指标的详细解释:

时间复杂度

  1. 最好情况(最优时间复杂度):当输入数组已经是排序好的情况下,冒泡排序只需进行一轮遍历就可以判断出数组已经有序,此时的时间复杂度为 O(n),其中n是数组的长度。
  1. 最坏情况(最劣时间复杂度):当输入数组是逆序的,即每个元素都位于其正确位置的对面,冒泡排序需要进行n-1轮遍历,每轮遍历中都需要进行n-i次比较(因为每轮都会把一个元素放到最终位置,所以比较次数递减),总比较次数接近n(n-1)/2,因此最坏情况下的时间复杂度为 O(n^2)
  1. 平均时间复杂度:考虑到各种随机排列的可能性,冒泡排序的平均时间复杂度也是 O(n^2)

空间复杂度

冒泡排序是一种原地排序算法,它不需要额外的存储空间来存放数据,除了几个用于交换的临时变量。因此,它的空间复杂度为 O(1)

稳定性

冒泡排序是稳定的排序算法。这意味着相等的元素在排序前后相对位置不会改变。这是因为冒泡排序在交换元素时只会交换不满足排序条件的相邻元素,如果元素相等则不会进行交换,从而保持了稳定性。

总结

尽管冒泡排序由于其简单易懂而常用于教学,但由于其较高的时间复杂度,在处理大量数据时效率低下,通常不推荐在实际应用中使用,特别是在数据量大的场景下。在需要高效排序的场合,更高效的算法如快速排序、归并排序或堆排序等是更好的选择。然而,冒泡排序在小规模数据或者几乎已排序的数据集上可能表现得还可以接受,特别是经过优化(如添加提前终止的条件)后。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1697712.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【大模型部署】在C# Winform中使用文生图Stable Diffusion XL 模型

【大模型部署】在C# Winform中使用文生图Stable Diffusion XL 模型 前言 整了一个在C# Winform中调用文生图Stable Diffusion XL的小程序&#xff0c;基于百度智能云千帆平台 步骤 如何注册百度智能云和创建应用&#xff0c;获取API 密钥等和在之前的博客中基本相同&#…

单日收益1000+看了就会的项目,最新灵异短视频项目,简单好上手可放大操作

各位好友&#xff0c;佳哥在此与大伙儿聊聊一项神秘莫测的短视频项目。你或许会想&#xff0c;“又是一个视频创作项目&#xff1f;” 但别急&#xff0c;这个项目与众不同&#xff0c;日入千元不再是梦&#xff0c;而且它的易用性让人惊喜&#xff0c;无论你是初学者还是资深玩…

面向对象------多态

1.多态的定义 通俗来说&#xff0c;当同一种行为或者事情发生在不同的对象上&#xff0c;这些行为或者事情最终得到的结果不同。 注意&#xff1a;多态要发生在继承的基础上。 例如&#xff1a;彩色打印机和黑白打印机。 彩色打印机和黑白打印机是不同的对象&#xff0c;但…

兵器室管控系统|DW-306是一套成熟系统

概述 智慧兵器室管理系统&#xff08;DW-S306&#xff09;是依托互3D技术、大数据、RFID技术、数据库技术、AI、视频分析技术对RFID智能仓库进行统一管理、分析的信息化、智能化、规范化的系统。 本解决方案利用现有内部网络&#xff0c;部署部队智能兵器室管理系统&#xff…

Python并发编程学习记录

1、初识并发编程 1.1、串行&#xff0c;并行&#xff0c;并发 串行(serial)&#xff1a;一个cpu上按顺序完成多个任务&#xff1b; 并行(parallelism)&#xff1a;任务数小于或等于cup核数&#xff0c;多个任务是同时执行的&#xff1b; 并发(concurrency)&#xff1a;一个…

小浪助手下载学浪视频的简单步骤

你是否想轻松下载学浪高清视频&#xff1f;快来尝试小浪助手&#xff0c;这是你不可错过的下载神器&#xff01;简单几步操作&#xff0c;即可轻松下载你所需的学浪视频&#xff0c;节省时间&#xff0c;提高效率&#xff01; 首先我已经打包好了小浪助手&#xff0c;有需要的…

DOS学习-目录与文件应用操作经典案例-attrib

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一.前言 二.使用 三.案例 一.前言 DOS系统中的attrib命令是一个用于显示或更改文件&#…

内网渗透—SMB隧道正反向连接防火墙规则绕过CS上线

1、前言 这篇文章主要是说一下这个用于横向移动的SMB隧道&#xff0c;已经如何使用smb隧道去进行横向移动。 2、实验环境 实验环境和上一篇的差不多&#xff0c;主要是加了个防火墙。 windows server2012 192.168.145.131&#xff08;外网&#xff09; 192.168.22.134&…

【NumPy】关于numpy.flatten()函数,看这一篇文章就够了

&#x1f9d1; 博主简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

头晕、心悸…你们小年轻配不上张俊杰的霸王茶姬,还要奔上市

近日&#xff0c;有多名网友在社交平台反映称&#xff0c;自己在喝了霸王茶姬的新品“万里木兰”奶茶后&#xff0c;出现了失眠、头晕、心悸等不同程度的不适症状&#xff0c;霸王茶姬方面则表示“可能是茶多酚过敏”。 而就在几天前举行的“2024年国际茶日现代东方茶创新论坛…

全局光照技术在AI去衣中的革命性角色

引言&#xff1a; 随着计算机视觉和深度学习技术的飞速发展&#xff0c;AI去衣技术已经逐渐成为图像处理和计算机图形学领域的一个热门话题。这种技术旨在通过算法模型去除或替换图像中的衣物&#xff0c;以服务于娱乐、电子商务、虚拟试衣等多种应用场景。而在实现高质量、真实…

getters的使用

getters的使用 如果state中的数据需要经过处理再使用&#xff0c;就可以利用getters函数

django在线考试系统-计算机毕业设计源码78268

摘 要 本论文主要论述了如何使用python语言、Django框架开发一个在线考试系统&#xff0c;本系统将严格按照软件开发流程&#xff0c;进行各个阶段的工作&#xff0c;面向对象编程思想进行项目开发。在引言中&#xff0c;作者将论述该系统的当前背景以及系统开发的目的&#xf…

VMware虚拟机上安装麒麟V10操作系统

一、安装VMware 在前面的文章中我有具体介绍过如何安装VMware软件&#xff0c;这里就不具体介绍了&#xff0c;需要的同学可以点下面的连接进行下载安装。 玩转Linux—如何在Linux环境中部署MySQL、Redis和nginx_linux系统mysql、redis 主备怎么做-CSDN博客文章浏览阅读1k次&a…

每日百万交易的支付系统,如何设置JVM堆内存大小?

每日百万交易的支付系统,如何设置JVM堆内存大小? 1、支付背景的引入2、支付的核心业务流程3、每日百万交易支付系统的压力在哪里?4、支付系统每秒钟需要处理多少笔支付单5、每个支付订单处理需要耗时多久6、每个支付订单大概需要多大的内存空间7、每秒发起的支付请求对内存的…

c#核心学习1

一、面向对象的概念 1.面向过程编程 2.面向对象编程 3.为什么要学习面向对象编程 提高代码复用率、提高开发效率、提高程序可拓展性、清晰的逻辑关系 4.如何学习 二、面向对象--封装 1&#xff09;类和对象 1.什么是类 2.类申明在哪里 类一般声明在namespace语句块中 3.…

电商API接口(api商品数据)【电商商品实时数据采集API接口】

众多品牌选择电商API实时数据采集接口进行采购&#xff0c;主要是出于以下几个重要原因&#xff1a; 第一&#xff0c;高效便捷。比价工具通过自动化的方式获取价格信息&#xff0c;避免了繁琐的人工操作&#xff0c;大大节省了时间和精力。 第二&#xff0c;精准比较。API比价…

AIGC 003-Controlnet升级你的SD让图像生成更加可控!

AIGC 003-Controlnet升级你的SD让图像生成更加可控&#xff01; 文章目录 0 论文工作1 论文方法2 效果 0 论文工作 ControlNet 论文 (Adding Conditional Control to Text-to-Image Diffusion Models) 提出了一种名为 ControlNet 的神经网络结构&#xff0c;旨在为大型文本到图…

IEDA常用快捷键(后续更新ing)

1. 快速生成语句 1.快速生成main()方法 psvm或者main回车 2.快速生成输出语句 sout,回车 3.快速生成for循环 fori或者itar,回车 2.快捷键 含义操作查找文本CtrlF替换文本CtrlR单行注释Ctrl/多行注释CtrlShift/格式化CtrlAltL复制当前内容至下一行CtrlD补全代码Alt/快速生成…

实战复盘:内网环境渗透ms-SQL数据库

渗透环境&#xff1a;如下图所示&#xff0c;web服务器、ms-SQL服务器、PC客户端在同一个网络中&#xff0c;彼此之间&#xff0c;没有路由器或防火墙的隔离&#xff0c;这是一种危险的网络结构&#xff0c;入侵ms-SQL服务器&#xff0c;非常容易。&#xff08;实战中&#xff…