【算法基础】冒泡排序算法 - JAVA

一、算法基础

1.1 什么是冒泡排序

冒泡排序是一种简单直观的比较排序算法。它重复地走访待排序的数列,依次比较相邻两个元素,如果顺序错误就交换它们,直到没有元素需要交换为止。

1.2 基本思想

  • 比较相邻元素:从头开始,两两比较相邻元素
  • 交换位置:如果前一个元素大于后一个元素,则交换位置
  • 重复操作:每完成一次迭代,最大的元素会"冒泡"到数组末尾
  • 多次迭代:重复以上步骤,每次排除已排好序的末尾元素

1.3 时间复杂度

  • 最好情况:O(n),当数组已经排好序
  • 最坏情况:O(n²),当数组逆序排列
  • 平均情况:O(n²)

二、冒泡排序的分类

2.1 标准冒泡排序

标准版本每次将最大元素冒泡到末尾:

  • 外层循环:控制排序轮数,最多n-1轮
  • 内层循环:控制每轮比较次数,逐渐减少
  • 无优化:即使数组已排序仍会执行全部循环

2.2 优化冒泡排序

通过标记变量检测一轮比较中是否有交换发生:

  • 设置标记:初始假设本轮无交换
  • 发生交换:更新标记变量
  • 提前终止:若一轮比较无交换发生,则排序完成

三、冒泡排序实现

3.1 标准实现

public class BubbleSort {/*** 标准冒泡排序算法* @param arr 待排序数组*/public static void bubbleSort(int[] arr) {int n = arr.length;// 外层循环控制排序轮数for (int i = 0; i < n - 1; i++) {// 内层循环进行相邻元素比较和交换// 每轮结束后,最大的i+1个元素已经排好序for (int j = 0; j < n - i - 1; j++) {// 如果当前元素大于下一个元素,交换它们if (arr[j] > arr[j + 1]) {int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}}
}

3.2 优化实现

public class OptimizedBubbleSort {/*** 优化版冒泡排序算法* @param arr 待排序数组*/public static void bubbleSort(int[] arr) {int n = arr.length;boolean 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]) {// 交换元素int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;// 标记发生了交换swapped = true;}}// 如果没有发生交换,说明数组已经有序,提前结束if (!swapped) {break;}}}
}

3.3 双向冒泡排序(鸡尾酒排序)

public class CocktailSort {/*** 双向冒泡排序(鸡尾酒排序)算法* @param arr 待排序数组*/public static void cocktailSort(int[] arr) {int left = 0;int right = arr.length - 1;boolean swapped;while (left < right) {swapped = false;// 从左向右,将最大元素冒泡到右侧for (int i = left; i < right; i++) {if (arr[i] > arr[i + 1]) {int temp = arr[i];arr[i] = arr[i + 1];arr[i + 1] = temp;swapped = true;}}// 如果没有交换,数组已经有序if (!swapped) {break;}right--; // 最大元素已经到位,缩小右边界swapped = false;// 从右向左,将最小元素冒泡到左侧for (int i = right; i > left; i--) {if (arr[i] < arr[i - 1]) {int temp = arr[i];arr[i] = arr[i - 1];arr[i - 1] = temp;swapped = true;}}// 如果没有交换,数组已经有序if (!swapped) {break;}left++; // 最小元素已经到位,缩小左边界}}
}

四、算法分析与优化

4.1 理论推导

冒泡排序的工作原理可以用以下数学表达式描述:

  • 比较次数:(n-1) + (n-2) + ... + 1 = n(n-1)/2
  • 最大交换次数:同上 n(n-1)/2
  • 元素移动次数:最多3×n(n-1)/2(每次交换需要3次移动)

4.2 优化策略

  1. 提前终止优化:如前述,检测是否有交换发生
  2. 记录最后交换位置:每轮记录最后一次交换的位置,下一轮只需扫描到该位置即可
  3. 奇偶交替扫描:类似鸡尾酒排序,减少"乌龟"(小元素靠后)的情况
public class EnhancedBubbleSort {/*** 记录最后交换位置的优化冒泡排序* @param arr 待排序数组*/public static void bubbleSort(int[] arr) {int n = arr.length;int lastSwappedIndex = n - 1;int newLastSwappedIndex;while (lastSwappedIndex > 0) {newLastSwappedIndex = 0;for (int i = 0; i < lastSwappedIndex; i++) {if (arr[i] > arr[i + 1]) {// 交换元素int temp = arr[i];arr[i] = arr[i + 1];arr[i + 1] = temp;// 记录最后交换的位置newLastSwappedIndex = i;}}// 更新下一轮排序的终止位置lastSwappedIndex = newLastSwappedIndex;}}
}

五、完整示例程序

public class BubbleSortDemo {public static void main(String[] args) {// 测试数据int[] arr = {64, 34, 25, 12, 22, 11, 90};System.out.println("原始数组: ");printArray(arr);// 执行优化版冒泡排序optimizedBubbleSort(arr);System.out.println("\n排序后数组: ");printArray(arr);}/*** 优化的冒泡排序实现*/public static void optimizedBubbleSort(int[] arr) {int n = arr.length;boolean 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]) {swap(arr, j, j + 1);swapped = true;}}// 如果没有发生交换,数组已经有序if (!swapped) {System.out.println("提前结束于第 " + (i + 1) + " 轮");break;}}}/*** 交换数组中两个元素*/private static void swap(int[] arr, int i, int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}/*** 打印数组*/private static void printArray(int[] arr) {for (int num : arr) {System.out.print(num + " ");}System.out.println();}
}

六、总结

冒泡排序是一种经典的排序算法,其特点如下:

6.1 优点

  • 实现简单:代码直观易懂,适合教学使用
  • 稳定性好:相等元素不会改变相对顺序
  • 原地排序:不需要额外空间
  • 自适应性:对于部分有序数据效率较高

6.2 缺点

  • 效率低下:平均时间复杂度为O(n²)
  • 比较次数多:即使数据已经有序,基本版本仍需大量比较

6.3 适用场景

  • 小规模数据:元素数量较少时表现尚可
  • 教学演示:算法思想简单直观
  • 接近有序数据:优化版本在这种情况下效率较高

冒泡排序虽然在大规模数据中效率不高,但其思想简单,实现容易,是学习排序算法的良好起点。在实际应用中,可根据数据特性选择更高效的排序算法,如快速排序、归并排序等。

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

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

相关文章

0902Redux_状态管理-react-仿低代码平台项目

文章目录 1 Redux 概述1.1 核心概念1.2 基本组成1.3 工作流程1.4 中间件&#xff08;Middleware&#xff09;1.5 适用场景1.6 优缺点1.7 Redux Toolkit&#xff08;现代推荐&#xff09;1.8 与其他工具的对比1.9 总结 2 todoList 待办事项案例3 Redux开发者工具3.1 核心功能3.2…

《ATPL地面培训教材13:飞行原理》——第6章:阻力

翻译&#xff1a;Leweslyh&#xff1b;工具&#xff1a;Cursor & Claude 3.7&#xff1b;过程稿 第6章&#xff1a;阻力 目录 引言寄生阻力诱导阻力减少诱导阻力的方法升力对寄生阻力的影响飞机总阻力飞机总重量对总阻力的影响高度对总阻力的影响构型对总阻力的影响速度稳…

C++总结01-类型相关

一、数据存储 1.程序数据段 • 静态&#xff08;全局&#xff09;数据区&#xff1a;全局变量、静态变量 • 堆内存&#xff1a;程序员手动分配、手动释放 • 栈内存&#xff1a;编译器自动分配、自动释放 • 常量区&#xff1a;编译时大小、值确定不可修改 2.程序代码段 •…

【Hot 100】94. 二叉树的中序遍历

目录 引言二叉树的中序遍历我的解题代码优化更清晰的表述建议&#xff1a; &#x1f64b;‍♂️ 作者&#xff1a;海码007&#x1f4dc; 专栏&#xff1a;算法专栏&#x1f4a5; 标题&#xff1a;【Hot 100】94. 二叉树的中序遍历❣️ 寄语&#xff1a;书到用时方恨少&#xff…

大语言模型(LLMs)微调技术总结

文章目录 全面总结当前大语言模型&#xff08;LLM&#xff09;微调技术1. 引言2. 为什么需要微调&#xff1f;3. 微调技术分类概览4. 各种微调技术详细介绍4.1 基础微调方法4.1.1 有监督微调&#xff08;Supervised Fine-Tuning, SFT&#xff09;4.1.2 全参数微调&#xff08;F…

解决Maven项目中报错“java不支持版本6即更高的版本 7”

错误背景 当Maven项目编译或运行时出现错误提示 Java不支持版本6即更高的版本7&#xff0c;通常是由于项目配置的JDK版本与当前环境或编译器设置不一致导致的。例如&#xff1a; 项目配置的Java版本为6或7&#xff0c;但实际使用的是JDK 17。Maven或IDE的编译器未正确指定目标…

C++笔记-多态(包含虚函数,纯虚函数和虚函数表等)

1.多态的概念 多态(polymorphism)的概念:通俗来说&#xff0c;就是多种形态。多态分为编译时多态(静态多态)和运行时多态(动态多态)&#xff0c;这里我们重点讲运行时多态&#xff0c;编译时多态(静态多态)和运行时多态(动态多态)。编译时多态(静态多态)主要就是我们前面讲的函…

【Unity】MVP框架的使用例子

在提到MVP之前&#xff0c;可以先看看这篇MVC的帖子&#xff1a; 【Unity】MVC的简单分享以及一个在UI中使用的例子 MVC的不足之处&#xff1a; 在MVC的使用中&#xff0c;会发现View层直接调用了Model层的引用&#xff0c;即这两个层之间存在着一定的耦合性&#xff0c;而MV…

前端js学算法-实践

1、两数之和 const twoSum (nums, target) > {const obj {}for (let m 0; m < nums.length; m) {const cur nums[m]const diff target - curif(obj.hasOwnProperty(diff)){ // 查询对象中是否存在目标值-当前值键值对console.log([obj[diff], m]) // 存在则直接获取…

《MATLAB实战训练营:从入门到工业级应用》趣味入门篇-用声音合成玩音乐:MATLAB电子琴制作(超级趣味实践版)

《MATLAB实战训练营&#xff1a;从入门到工业级应用》趣味入门篇-用声音合成玩音乐&#xff1a;MATLAB电子琴制作&#xff08;超级趣味实践版&#xff09; 开篇&#xff1a;当MATLAB遇见音乐 - 一场数字与艺术的浪漫邂逅 想象一下&#xff0c;你正坐在一台古老的钢琴前&#x…

实战探讨:为什么 Redis Zset 选择跳表?

在了解了跳表的原理和实现后&#xff0c;一个常见的问题&#xff08;尤其是在面试中&#xff09;随之而来&#xff1a;为什么像 Redis 的有序集合 (Zset) 这样的高性能组件会选择使用跳表&#xff0c;而不是大家熟知的平衡树&#xff08;如红黑树&#xff09;呢&#xff1f; 对…

数据结构-线性结构(链表、栈、队列)实现

公共头文件common.h #define TRUE 1 #define FALSE 0// 定义节点数据类型 #define DATA_TYPE int单链表C语言实现 SingleList.h #pragma once#include "common.h"typedef struct Node {DATA_TYPE data;struct Node *next; } Node;Node *initList();void headInser…

高中数学联赛模拟试题精选学数学系列第3套几何题

△ A B C \triangle ABC △ABC 的内切圆 ⊙ I \odot I ⊙I 分别与边 B C BC BC, C A CA CA, A B AB AB 相切于点 D D D, E E E, F F F, D D ′ DD DD′ 为 ⊙ I \odot I ⊙I 的直径, 过圆心 I I I 作直线 A D ′ AD AD′ 的垂线 l l l, 直线 l l l 分别与 D E DE…

使用 ossutil 上传文件到阿里云 OSS

在处理文件存储和传输时&#xff0c;阿里云的对象存储服务&#xff08;OSS&#xff09;是一个非常方便的选择。特别是在需要批量上传文件或通过命令行工具进行文件管理时&#xff0c;ossutil提供了强大的功能。本文将详细说明如何使用 ossutil 上传文件到阿里云 OSS&#xff0c…

DeepSeek与MySQL:开启数据智能新时代

目录 一、引言&#xff1a;技术融合的力量二、DeepSeek 与 MySQL&#xff1a;技术基石2.1 DeepSeek 技术探秘2.2 MySQL 数据库深度解析 三、DeepSeek 与 MySQL 集成&#xff1a;从理论到实践3.1 集成原理剖析3.2 集成步骤详解 四、应用案例&#xff1a;实战中的价值体现4.1 电商…

WebAPI项目从Newtonsoft.Json迁移到System.Text.Json踩坑备忘

1.控制器层方法返回类型不能为元组 控制器层方法返回类型为元组时&#xff0c;序列化结果为空。 因为元组没有属性只有field&#xff0c;除非使用IncludeFields参数专门指定&#xff0c;否则使用System.Text.Json进行序列化时不会序列化field var options new JsonSerializ…

202553-sql

目录 一、196. 删除重复的电子邮箱 - 力扣&#xff08;LeetCode&#xff09; 二、602. 好友申请 II &#xff1a;谁有最多的好友 - 力扣&#xff08;LeetCode&#xff09; 三、176. 第二高的薪水 - 力扣&#xff08;LeetCode&#xff09; 一、196. 删除重复的电子邮箱 - 力扣…

Spring Boot的GraalVM支持:构建低资源消耗微服务

文章目录 引言一、GraalVM原生镜像技术概述二、Spring Boot 3.x的GraalVM支持三、适配GraalVM的关键技术点四、构建原生镜像微服务实例五、性能优化与最佳实践总结 引言 微服务架构已成为企业应用开发的主流模式&#xff0c;但随着微服务数量的增加&#xff0c;资源消耗问题日…

pip 常用命令及配置

一、python -m pip install 和 pip install 的区别 在讲解 pip 的命令之前&#xff0c;我们有必要了解一下 python -m pip install 和 pip install 的区别&#xff0c;以便于我们在不同的场景使用不同的方式。 python -m pip install 命令使用 python 可执行文件将 pip 模块作…

Vue高级特性实战:自定义指令、插槽与路由全解析

一、自定义指令 1.如何自定义指令 ⑴.全局注册语法 通过 Vue.directive 方法注册&#xff0c;语法格式为&#xff1a; Vue.directive(指令名, {// 钩子函数&#xff0c;元素插入父节点时触发&#xff08;仅保证父节点存在&#xff0c;不一定已插入文档&#xff09;inserted(…