算法学习笔记:11.冒泡排序——从原理到实战,涵盖 LeetCode 与考研 408 例题

在排序算法的大家族中,冒泡排序是最基础也最经典的算法之一。它的核心思想简单易懂,通过重复地走访待排序序列,一次比较两个相邻的元素,若它们的顺序错误就把它们交换过来,直到没有需要交换的元素为止。虽然冒泡排序的时间复杂度较高,在大规模数据排序中并不常用,但它是理解排序算法思想的绝佳入门案例,也是计算机考研 408 和算法学习中的基础内容。

冒泡排序的基本概念

冒泡排序(Bubble Sort)之所以被称为 “冒泡”,是因为在排序过程中,较小的元素会像水中的气泡一样逐渐 “上浮” 到序列的顶端,而较大的元素则会 “下沉” 到序列的末端。

例如,对于一个无序序列 [5, 2, 9, 1, 5, 6],使用冒泡排序进行排序时,过程如下:

  • 第一轮比较后,最大的元素 9 会 “下沉” 到序列的最后位置,序列变为 [2, 5, 1, 5, 6, 9]。
  • 第二轮比较后,第二大的元素 6 会 “下沉” 到倒数第二个位置,序列变为 [2, 1, 5, 5, 6, 9]。
  • 继续重复这个过程,直到整个序列变得有序。

冒泡排序的算法思想

冒泡排序的核心思想是通过相邻元素的比较和交换,使较大的元素逐渐 “下沉” 到序列的末端。其基本思路遵循以下步骤:

  1. 遍历序列:从序列的第一个元素开始,依次比较相邻的两个元素。
  1. 比较与交换:如果前一个元素大于后一个元素,则交换这两个元素的位置,确保较大的元素向后移动。
  1. 重复迭代:完成一轮遍历后,最大的元素会 “下沉” 到序列的最后一个位置。然后忽略已经 “下沉” 到位的元素,对剩余的元素重复上述遍历、比较和交换过程。
  1. 终止条件:当在一轮遍历中没有发生任何元素交换时,说明序列已经有序,排序结束。

冒泡排序的关键在于 “逐轮下沉最大元素”,每一轮排序都会确定一个元素的最终位置。对于长度为n的序列,最多需要进行n-1轮排序(在最坏情况下,即序列完全逆序时)。

冒泡排序的解题思路

使用冒泡排序解决实际问题时,通常遵循以下步骤:

  1. 确定待排序序列:明确需要排序的数据集合,可以是数组、列表等数据结构。
  1. 初始化控制变量:设置一个标志变量(如swapped),用于记录在一轮遍历中是否发生了元素交换,初始值为false。
  1. 执行多轮排序
    • 每轮遍历从序列的第一个元素开始,到未排序部分的最后一个元素结束。
    • 在遍历过程中,比较相邻元素,若前大后小则交换,并将标志变量设为true。
    • 一轮遍历结束后,检查标志变量。若为false,说明序列已有序,退出循环;若为true,则重置标志变量,继续下一轮排序。
  1. 返回排序结果:排序完成后,返回有序的序列。

通过优化标志变量,可以避免在序列已经有序后继续不必要的遍历,提高算法效率。

LeetCode 例题及 Java 代码实现

例题 1:排序数组(LeetCode 912)

给你一个整数数组 nums,请你将该数组升序排列。

解题思路

本题是典型的排序问题,可直接使用冒泡排序求解。按照上述解题思路,通过多轮遍历、比较和交换,将数组升序排列。

Java 代码实现
import java.util.Arrays;public class SortArray {public int[] sortArray(int[] nums) {int n = nums.length;// 外层循环控制排序轮数,最多n-1轮for (int i = 0; i < n - 1; i++) {boolean swapped = false;// 内层循环控制每轮比较的范围,每轮结束后最大元素已沉底,无需再比较for (int j = 0; j < n - 1 - i; j++) {if (nums[j] > nums[j + 1]) {// 交换相邻元素int temp = nums[j];nums[j] = nums[j + 1];nums[j + 1] = temp;swapped = true;}}// 若本轮无交换,说明数组已有序,提前退出if (!swapped) {break;}}return nums;}public static void main(String[] args) {SortArray solution = new SortArray();int[] nums = {5, 2, 9, 1, 5, 6};int[] sortedNums = solution.sortArray(nums);System.out.println(Arrays.toString(sortedNums)); // 输出:[1, 2, 5, 5, 6, 9]}}

例题 2:最大间距(LeetCode 164)

给定一个无序的数组 nums,返回数组在排序之后,相邻元素之间最大的差值。如果数组元素个数小于 2,则返回 0。

解题思路

本题可先使用冒泡排序对数组进行排序,然后遍历排序后的数组,计算相邻元素的差值,记录最大差值。需要注意的是,由于冒泡排序在处理大规模数据时效率较低,本题仅作为冒泡排序应用的示例,实际解题中更推荐使用基数排序等高效算法。

Java 代码实现
public class MaximumGap {public int maximumGap(int[] nums) {int n = nums.length;if (n < 2) {return 0;}// 先使用冒泡排序对数组排序bubbleSort(nums);// 计算相邻元素的最大差值int maxGap = 0;for (int i = 1; i < n; i++) {maxGap = Math.max(maxGap, nums[i] - nums[i - 1]);}return maxGap;}// 冒泡排序实现private void bubbleSort(int[] nums) {int n = nums.length;for (int i = 0; i < n - 1; i++) {boolean swapped = false;for (int j = 0; j < n - 1 - i; j++) {if (nums[j] > nums[j + 1]) {int temp = nums[j];nums[j] = nums[j + 1];nums[j + 1] = temp;swapped = true;}}if (!swapped) {break;}}}public static void main(String[] args) {MaximumGap solution = new MaximumGap();int[] nums = {3, 6, 9, 1};System.out.println(solution.maximumGap(nums)); // 输出:3(排序后为[1,3,6,9],最大间距为6-3=3)}}

冒泡排序与考研 408

在计算机考研 408 中,冒泡排序是数据结构部分的基础考点,主要涉及以下几个方面:

  1. 算法原理与实现:考研 408 常考查冒泡排序的基本原理、执行过程和代码实现。要求考生能够手动模拟冒泡排序在给定序列上的每一步操作,包括元素的比较、交换和每轮结束后的序列状态。例如,给定一个逆序数组,写出冒泡排序每一轮后的结果。
  1. 时间复杂度与空间复杂度分析
    • 时间复杂度
      • 最坏情况:当序列完全逆序时,每轮都需要进行n-i-1次比较和交换(i为轮次),总比较次数为(n-1)+(n-2)+...+1 = n(n-1)/2,时间复杂度为\(O(n^2)\)。
      • 最好情况:当序列已经有序时,只需进行 1 轮遍历(n-1次比较),且无交换操作,时间复杂度为\(O(n)\)。
      • 平均情况:时间复杂度为\(O(n^2)\)。
    • 空间复杂度:冒泡排序是原地排序算法,仅需要常数级别的额外空间(用于临时变量和标志变量),空间复杂度为\(O(1)\)。
  1. 算法特性
    • 稳定性:冒泡排序是稳定的排序算法。在比较相邻元素时,只有当nums[j] > nums[j+1]时才进行交换,相等元素的相对顺序不会改变。
    • 原地性:不需要额外的辅助空间,直接在原序列上进行排序。
    • 适应性:通过标志变量优化后,对于接近有序的序列,效率会显著提高(最好情况为\(O(n)\))。
  1. 与其他排序算法的对比:考研 408 中常将冒泡排序与插入排序、选择排序等简单排序算法进行对比,考查它们在时间复杂度、空间复杂度、稳定性、适用场景等方面的差异。例如:
    • 冒泡排序和插入排序的最好时间复杂度都是\(O(n)\),但插入排序在实际应用中通常比冒泡排序更高效(减少了元素交换的次数)。
    • 选择排序的时间复杂度始终为\(O(n^2)\),且不稳定,而冒泡排序在最好情况下更优且稳定。
  1. 算法优化:考研中可能会考查冒泡排序的优化方法,除了上述的标志变量优化外,还包括 “记录最后一次交换的位置”,以此确定下一轮遍历的终点(因为最后一次交换位置之后的元素已经有序),进一步减少比较次数。

总结

冒泡排序作为最基础的排序算法之一,虽然在大规模数据排序中效率不高,但其简单直观的思想和清晰的执行过程,使其成为理解排序算法的入门首选。通过本文的学习,我们掌握了冒泡排序的算法思想、解题思路、LeetCode 实战应用以及考研 408 中的考点。

在学习过程中,建议结合手动模拟排序过程加深对算法的理解,同时对比其他简单排序算法(如插入排序、选择排序)的异同,形成系统的知识体系。对于考研 408 考生,需重点掌握冒泡排序的时间复杂度分析、稳定性判断以及与其他算法的对比,确保在考试中能够准确解答相关问题。

希望本文能够帮助读者更深入地理解冒泡排序,并在实际项目中发挥其优势。谢谢阅读!


希望这份博客能够帮助到你。如果有其他需要修改或添加的地方,请随时告诉我。

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

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

相关文章

Linux小白学习基础内容

记录第一天重新学习2025/7/10 15&#xff1a;467/10 17&#xff1a;02这里面一个命令带多个参数举例&#xff08;多个参数之间用空格隔开&#xff09;ls&#xff08;命令&#xff09; ~ / /etc/&#xff08;参数&#xff09; :这里就是同时查看主机的家目录&#xff0c;根目…

从零开始搭建深度学习大厦系列-2.卷积神经网络基础(5-9)

(1)本人挑战手写代码验证理论&#xff0c;获得一些AI工具无法提供的收获和思考&#xff0c;对于一些我无法回答的疑问请大家在评论区指教&#xff1b; (2)本系列文章有很多细节需要弄清楚&#xff0c;但是考虑到读者的吸收情况和文章篇幅限制&#xff0c;选择重点进行分享&…

【iOS设计模式】深入理解MVC架构 - 重构你的第一个App

目录 一、MVC模式概述 二、创建Model层 1. 新建Person模型类 2. 实现Person类 三、重构ViewController 1. 修改ViewController.h 2. 重构ViewController.m 四、MVC组件详解 1. Model&#xff08;Person类&#xff09; 2. View&#xff08;Storyboard中的UI元素&#x…

前端项目集成lint-staged

lint-staged (lint-staged) 这个插件可以只针对进入git暂存区中的代码进行代码格式检查与修复&#xff0c;极大提升效率&#xff0c;避免扫描整个项目文件&#xff0c;代码风格控制 eslint prettier stylelint 看这两篇文章 前端项目vue3项目集成eslint9.x跟prettier 前端项…

李宏毅genai笔记:模型编辑

0 和post training的区别直接用post training的方法是有挑战的&#xff0c;因为通常训练资料只有一笔而且之后不管问什么问题&#xff0c;都有可能只是这个答案了1 模型编辑的评估方案 reliability——同样的问题&#xff0c;需要是目标答案generalization——问题&#xff08;…

Oracle:union all和union区别

UNION ALL和UNION在Oracle中的主要区别体现在处理重复记录、性能及结果排序上&#xff1a;处理重复记录‌UNION‌&#xff1a;自动去除重复记录&#xff0c;确保最终结果唯一。‌UNION ALL‌&#xff1a;保留所有记录&#xff0c;包括完全重复的行。性能表现‌UNION‌&#xff…

[C#/.NET] 内网开发中如何使用 System.Text.Json 实现 JSON 解析(无需 NuGet)

在实际的企业开发环境中&#xff0c;尤其是内网隔离环境&#xff0c;开发人员经常面临无法使用 NuGet 安装外部包的问题。对于基于 .NET Framework 4.8 的应用&#xff0c;JSON 解析是一个常见的需求&#xff0c;但初始项目中往往未包含任何 JSON 处理相关的程序集。这时&#…

JVM(Java 虚拟机)的介绍

JVM原理JVM 核心架构与工作流程1. 类加载机制&#xff08;Class Loading&#xff09;2. 运行时数据区&#xff08;Runtime Data Areas&#xff09;堆&#xff08;Heap&#xff09;方法区&#xff08;Method Area&#xff09;:元空间&#xff08;Metaspace&#xff09;公共区域虚…

Qt 信号槽的扩展知识

Qt 信号槽的扩展知识一、信号与槽的重载Qt信号与槽的重载问题注意事项示例场景二、一个信号连接多个槽1、直接连接多个槽2、使用lambda表达式连接3、连接顺序控制4、断开特定连接5、自动连接方式三、 多个信号连接一个槽基本连接语法使用QSignalMapper区分信号源&#xff08;Qt…

链表算法之【合并两个有序链表】

目录 LeetCode-21题 LeetCode-21题 将两个升序链表合并成一个新的升序链表并返回 class Solution {public ListNode mergeTwoLists(ListNode list1, ListNode list2) {if (list1 null)return list2;if (list2 null)return list1;ListNode dummyHead new ListNode();ListN…

Linux - firewall 防火墙

&#x1f525; 什么是 firewalld&#xff1f;firewalld 是一个动态管理防火墙的守护进程&#xff08;daemon&#xff09;&#xff0c;它提供了一个 D-Bus 接口来管理系统或用户的防火墙规则。与传统的静态 iptables 不同&#xff0c;firewalld 支持&#xff1a;区域&#xff08…

【GESP】C++二级真题 luogu-B4356 [GESP202506 二级] 数三角形

GESP C二级&#xff0c;2025年6月真题&#xff0c;多重循环&#xff0c;难度★✮☆☆☆。 题目题解详见&#xff1a;【GESP】C二级真题 luogu-B4356 [GESP202506 二级] 数三角形 | OneCoder 【GESP】C二级真题 luogu-B4356 [GESP202506 二级] 数三角形 | OneCoderGESP C二级&…

遥感影像岩性分类:基于CNN与CNN-EL集成学习的深度学习方法

遥感影像岩性分类&#xff1a;基于CNN与CNN-EL集成学习的深度学习方法 大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下遥感影像岩性分类&#xff1a;基于CNN与CNN-EL集成学习的深度学习方法。该方法充分利用了多源遥感数据的光谱和空间信息&#xff0c;同时结合…

【STM32 学习笔记】SPI通信协议

SPI通信协议 SPI协议是由摩托罗拉公司提出的通讯协议(Serial Peripheral Interface)&#xff0c;即串行外围设备接口&#xff0c; 是一种高速全双工的通信总线。它被广泛地使用在ADC、LCD等设备与MCU间&#xff0c;要求通讯速率较高的场合。   学习本章时&#xff0c;可与I2C…

Kafka如何做到消息不丢失

一、三种消息传递语义(Message Delivery Semantics):核心是“消息被消费处理的次数” Kafka的三种传递语义本质上描述的是“一条消息从生产到最终被消费者处理完成,可能出现的次数”,这由生产者的消息写入可靠性和消费者的offset提交策略共同决定。 1. At most once(最…

HEVC/H.265 码流分析工具 HEVCESBrowser 使用教程

引言 研究视频编解码的都知道&#xff0c;少不了各类的分析工具助力标准研究和算法开发&#xff0c;目前最出名的流媒体分析工具就是elecard系列&#xff0c;但基于一些原因可能大家用的都比较少。因此&#xff0c;找到合适的码流分析工具才是编解码研究的便捷途径&#xff0c…

量子计算+AI芯片:光子计算如何重构神经网络硬件生态

前言 前些天发现了一个巨牛的人工智能免费学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站 量子计算AI芯片&#xff1a;光子计算如何重构神经网络硬件生态 ——2025年超异构计算架构下的万亿参数模型训练革命 产业拐点&a…

linux 4.14 kernel屏蔽arm arch timer的方法

在 ARMv7 架构的单核 CPU 系统中&#xff0c;完全禁用 coretime 时钟中断&#xff08;通常是 ARM 私有定时器中断&#xff09;需要谨慎操作&#xff0c;因为这会导致调度器无法工作&#xff0c;系统可能失去响应。以下是实现方法及注意事项&#xff1a;方法 1&#xff1a;通过 …

[实战]调频(FM)和调幅(AM)信号生成(完整C语言实现)

调频&#xff08;FM&#xff09;和调幅&#xff08;AM&#xff09;信号生成 文章目录调频&#xff08;FM&#xff09;和调幅&#xff08;AM&#xff09;信号生成1. 调频&#xff08;FM&#xff09;和调幅&#xff08;AM&#xff09;信号原理与信号生成调幅&#xff08;AM&#…

【LeetCode 热题 100】21. 合并两个有序链表——(解法一)迭代法

Problem: 21. 合并两个有序链表 题目&#xff1a;将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 文章目录整体思路完整代码时空复杂度时间复杂度&#xff1a;O(M N)空间复杂度&#xff1a;O(1)整体思路 这段代码旨在解决…