冒泡排序(Bubble Sort)详细教程:Java实现与优化

一、什么是冒泡排序?

冒泡排序(Bubble Sort)是一种简单的排序算法,它的基本思想是通过两两比较相邻元素,将较大的元素“冒泡”到数列的末尾。每一轮遍历会将一个较大的元素放到正确的位置,直到整个数组有序。

冒泡排序的基本思想:
  1. 从数列的起始位置开始,依次比较相邻的元素。
  2. 如果前一个元素大于后一个元素,则交换它们的位置。
  3. 一轮遍历结束后,最大的元素会“冒泡”到数列的末尾。
  4. 重复上述过程,直到整个数列有序。

二、冒泡排序的工作原理

假设有一个数组 [64, 34, 25, 12, 22, 11],我们使用冒泡排序对其进行排序。以下是每个步骤的详细描述:

第一轮遍历:
  • 比较 6434,发现 64 > 34,所以交换它们,数组变为 [34, 64, 25, 12, 22, 11]
  • 比较 6425,发现 64 > 25,交换它们,数组变为 [34, 25, 64, 12, 22, 11]
  • 比较 6412,发现 64 > 12,交换它们,数组变为 [34, 25, 12, 64, 22, 11]
  • 比较 6422,发现 64 > 22,交换它们,数组变为 [34, 25, 12, 22, 64, 11]
  • 比较 6411,发现 64 > 11,交换它们,数组变为 [34, 25, 12, 22, 11, 64]

经过一轮遍历,最大的数 64 已经被排到了数组的末尾。

第二轮遍历:
  • 比较 3425,发现 34 > 25,交换它们,数组变为 [25, 34, 12, 22, 11, 64]
  • 比较 3412,发现 34 > 12,交换它们,数组变为 [25, 12, 34, 22, 11, 64]
  • 比较 3422,发现 34 > 22,交换它们,数组变为 [25, 12, 22, 34, 11, 64]
  • 比较 3411,发现 34 > 11,交换它们,数组变为 [25, 12, 22, 11, 34, 64]

经过第二轮遍历,第二大的数 34 被排到了倒数第二个位置。

第三轮遍历:
  • 比较 2512,发现 25 > 12,交换它们,数组变为 [12, 25, 22, 11, 34, 64]
  • 比较 2522,发现 25 > 22,交换它们,数组变为 [12, 22, 25, 11, 34, 64]
  • 比较 2511,发现 25 > 11,交换它们,数组变为 [12, 22, 11, 25, 34, 64]

经过第三轮遍历,第三大的数 25 被排到了倒数第三个位置。

三、Java实现冒泡排序

下面是冒泡排序的 Java 代码实现:

public class BubbleSort {

    // 冒泡排序算法
    public static void bubbleSort(int[] arr) {
        int n = arr.length;

        // 外层循环控制遍历次数
        for (int i = 0; i < n - 1; i++) {
            // 内层循环进行相邻元素的比较和交换
            for (int j = 0; j < n - 1 - i; j++) {
                // 比较相邻元素,若前者大于后者则交换
                if (arr[j] > arr[j + 1]) {
                    // 交换位置
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }

    // 打印数组
    public static void printArray(int[] arr) {
        for (int num : arr) {
            System.out.print(num + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        int[] arr = {64, 25, 12, 22, 11};

        System.out.println("原始数组:");
        printArray(arr);

        bubbleSort(arr);

        System.out.println("排序后的数组:");
        printArray(arr);
    }
}

四、冒泡排序的优化

虽然冒泡排序简单易懂,但它在效率上不够理想,尤其在数组较大时,性能表现较差。优化冒泡排序的方法之一是引入一个标志位 swapped 来判断是否发生了交换。

优化后的冒泡排序:
public class OptimizedBubbleSort {

    public static void bubbleSort(int[] arr) {
        int n = arr.length;

        // 外层循环控制遍历次数
        for (int i = 0; i < n - 1; i++) {
            boolean swapped = false;

            // 内层循环进行相邻元素的比较和交换
            for (int j = 0; j < n - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                    swapped = true;
                }
            }

            // 如果没有发生交换,提前终止
            if (!swapped) {
                break;
            }
        }
    }

    public static void printArray(int[] arr) {
        for (int num : arr) {
            System.out.print(num + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        int[] arr = {64, 25, 12, 22, 11};

        System.out.println("原始数组:");
        printArray(arr);

        bubbleSort(arr);

        System.out.println("排序后的数组:");
        printArray(arr);
    }
}

通过使用 swapped 标志位,在某一轮遍历没有发生交换时,我们可以提前终止排序过程,从而避免不必要的遍历,提升性能。

五、时间复杂度与空间复杂度分析

时间复杂度:
  • 最坏情况: 当输入数组是倒序排列时,每一轮内层循环都需要进行交换。总的比较次数为 O(n2)O(n^2)O(n2),所以时间复杂度为 O(n2)O(n^2)O(n2)。
  • 最好情况: 当输入数组已经是有序时,优化后的冒泡排序会提前终止,时间复杂度为 O(n)O(n)O(n)。
  • 平均情况: 对于无序数组,时间复杂度通常是 O(n2)O(n^2)O(n2)。
空间复杂度:

冒泡排序是一种原地排序算法,因此其空间复杂度为 O(1)O(1)O(1)。

六、总结

冒泡排序是一种简单易懂的排序算法,适用于小规模数据的排序。在处理大规模数据时,性能较差,因此在实际应用中我们更倾向于使用快速排序、归并排序等更高效的算法。尽管如此,冒泡排序仍然是理解排序算法的一个重要起点。

版权声明
  1. 本文内容属于原创,欢迎转载,但请务必注明出处和作者,尊重原创版权。
  2. 转载时,请附带原文链接并注明“本文作者:扣丁梦想家
  3. 禁止未经授权的商业转载。

如果您有任何问题或建议,欢迎留言讨论。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于SpringBoot的“古城景区管理系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“古城景区管理系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统整体功能图 系统首页界面 系统注册界面 景…

第五项修炼:打造学习型组织

“没有哪个教室比得上一个充满问题的团队。” — 彼得圣吉 最近有伙伴问我们&#xff0c;如何在组织中践行《第五项修炼&#xff1a;打造学习型组织》&#xff1f;我想和大家分享的是&#xff0c;这不仅仅是“学习”&#xff0c;更是通过结构和行为的深度结合&#xff0c;推动绩…

ubuntu22.04的docker容器中安装ssh服务

ubuntu22.04的docker容器中安装ssh服务&#xff0c;以便外部可以连接到容器中操作。 rootnode15:~# cat /etc/issue Ubuntu 22.04.5 LTS \n \l rootnode15:~# docker ps|grep qwen 7d3c36c37d36 vllm/vllm-openai:v0.7.3 "python3 -m …

LabVIEW 中 codeGenEngine.llb 工具库

codeGenEngine.llb 是 LabVIEW 2019 安装目录下C:\Program Files (x86)\National Instruments\LabVIEW 2019\vi.lib\Platform\路径下的工具库&#xff0c;主要用于代码生成相关的操作&#xff0c;帮助开发者在 LabVIEW 项目中便捷地实现自动化代码生成任务&#xff0c;提高开发…

基于LangChain4j调用火山引擎DeepSeek R1搭建RAG知识库实战指南

基于LangChain4j调用火山引擎DeepSeek R1搭建RAG知识库实战指南 基于LangChain4j调用火山引擎DeepSeek R1搭建RAG知识库实战指南 基于LangChain4j调用火山引擎DeepSeek R1搭建RAG知识库实战指南一、注册火山引擎账号二、RAG技术核心原理三、环境与工具准备1. 核心组件2. 依赖配…

基于YOLO11深度学习的医学X光骨折检测与语音提示系统【python源码+Pyqt5界面+数据集+训练代码】

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…

Unity百游修炼(2)——Brick_Breaker详细制作全流程

一、项目简介 Brick Breaker 是一款经典的打砖块游戏&#xff0c;本次案例将使用 Unity 引擎来实现该游戏的核心功能。 游戏画面如下&#xff1a; Brick_ breaker 二、项目结构概览和前期准备 &#xff08;1&#xff09;在 Unity 项目视图中&#xff0c;我们可以看到几个重要…

DeepSeek开源周Day2:DeepEP - 专为 MoE 模型设计的超高效 GPU 通信库

项目地址&#xff1a;https://github.com/deepseek-ai/DeepEP 开源日历&#xff1a;2025-02-24起 每日9AM(北京时间)更新&#xff0c;持续五天 (2/5)&#xff01; ​ ​ 引言 在大模型训练中&#xff0c;混合专家模型&#xff08;Mixture-of-Experts, MoE&#xff09;因其动…

前端面试基础知识整理(一)

1.vue生命周期 beforeCreate 创建 注入依赖 初始化非响应式数据 beforeCreate created 数据请求&#xff0c;初始化数据 设置全局时间监听 beforeMount挂载 模版编译完成后的调试 操作 dom初始化 操作dom初始化第三方插件 更新 在更新前查看 DOM 状态&#xff0c;不建议修改数据…

【单片机】MSP430MSP432入门

文章目录 0 前言1 开发方式选择2 CCS和开发相关软件3 Keil开发MSP4324 IAR for 430开发MSP4305 总结 0 前言 最近因为想学DSP&#xff0c;所以把之前卸载的CCS给装回来了&#xff0c;手头也还有之前电赛剩下的MSP430和MSP432的板子&#xff0c;由于年代久远&#xff0c;想着花点…

【Linux探索学习】第二十七弹——信号(上):Linux 信号基础详解

Linux学习笔记&#xff1a; https://blog.csdn.net/2301_80220607/category_12805278.html?spm1001.2014.3001.5482 前言&#xff1a; 前面我们已经将进程通信部分讲完了&#xff0c;现在我们来讲一个进程部分也非常重要的知识点——信号&#xff0c;信号也是进程间通信的一…

74道高级Java面试合集,java开发模式面试题

前言 今天我们来说说Redis为什么高性能&#xff1f;如何做高可用&#xff1f; Redis为什么这么快&#xff1f; Redis是单线程的&#xff0c;避免了多线程的上下文切换和并发控制开销&#xff1b;Redis大部分操作时基于内存&#xff0c;读写数据不需要磁盘I/O&#xff0c;所以速…

【江科协-STM32】5. 输出比较

1. 输出比较简介 OC(Output Compare)输出比较。 输出比较可以通过CNT&#xff08;CNT计数器&#xff09;与CCR寄存器值的关系&#xff0c;来对输出电平进行置1、置0或翻转的操作&#xff0c;用于输出一定频率和占空比的PWM波形。 :::tip CNT计数器是正向计数器。它只能正向累…

轻量级日志管理平台Grafana Loki

文章目录 轻量级日志管理平台Grafana Loki背景什么是Loki为什么使用 Grafana Loki&#xff1f;架构Log Storage Grafana部署使用基于 Docker Compose 安装 LokiMinIO K8s集群部署Loki采集Helm 部署方式和案例 参考 轻量级日志管理平台Grafana Loki 背景 在微服务以及云原生时…

使用 Postman 访问 Keycloak 端点

1. 引言 在本教程中&#xff0c;我们将首先快速回顾 OAuth 2.0、OpenID 和 Keycloak。然后&#xff0c;我们将了解 Keycloak REST API 以及如何在 Postman 中调用它们。 2. OAuth 2.0 OAuth 2.0 是一个授权框架&#xff0c;它允许经过身份验证的用户通过令牌向第三方授予访问…

WEB1~6通杀

##解题思路 这六道题&#xff0c;通杀了&#xff0c;只因为是PHP的特性 来&#xff0c;看web6&#xff0c;过滤最复杂的正则&#xff0c;而且不能解析成大于999的值&#xff0c;但是&#xff0c;php是弱类型的语言&#xff0c;我只要输入任意字符数字&#xff0c;最终值就为0&…

I2C协议简介:串行通信的关键技术

目录 一、总线通信基本概念 二、I2C总线协议介绍 1. 时序图解析 &#xff08;1&#xff09;起始信号 &#xff08;2&#xff09;应答信号 &#xff08;3&#xff09;终止信号 &#xff08;4&#xff09;设备地址 &#xff08;5&#xff09;I2C传输方法 ​编辑 &#…

第二十四:5.2【搭建 pinia 环境】axios 异步调用数据

第一步安装&#xff1a;npm install pinia 第二步&#xff1a;操作src/main.ts 改变里面的值的信息&#xff1a; <div class"count"><h2>当前求和为&#xff1a;{{ sum }}</h2><select v-model.number"n">  // .number 这里是…

Web漏洞——命令注入漏洞学习

一、什么是命令注入漏洞 想象一下&#xff0c;你家有一个智能管家机器人。这个机器人可以通过你发出的指令来完成各种任务&#xff0c;比如“请打开电视机、播放音乐、开灯等等”。你只需要对它说&#xff1a;“请打开电视”&#xff0c;它就会去执行这个任务。但是&#xff0…

大模型自动提示优化(APO)综述笔记

自大型语言模型&#xff08;LLMs&#xff09;出现以来&#xff0c;提示工程一直是各种自然语言处理&#xff08;NLP&#xff09;任务中激发期望响应的关键步骤。然而&#xff0c;由于模型的快速进步、任务的多样性和相关最佳实践的变化&#xff0c;提示工程对最终用户来说仍然是…