【排序算法】之冒泡排序

news2025/1/22 13:03:34

一、算法介绍

冒泡排序(Bubble Sort)是一种基础的排序算法,它的主要思想是通过重复遍历待排序的列表,比较每对相邻的元素并根据需要交换它们,使得每一遍遍历都能将未排序的最大(或最小)元素“冒泡”到正确的位置。以下是冒泡排序的详细步骤和特点:
1. 基本步骤:

  • 对于给定的未排序数组,从第一个元素开始,比较相邻的元素。
  • 如果前一个元素大于后一个元素,则交换它们的位置。
  • 对每一对相邻元素做同样的比较,从开始第一对到结尾的最后一对。这步做完后,最后的元素将会是最大的数。
  • 重复步骤1和2,但不包括最后一对,因为上一轮中它们已经排好序了。
  • 重复以上步骤,直到没有需要交换的元素,即数组完全排序。

2. 算法流程:

  • 一次完整的遍历称为一轮。
  • 每轮遍历中,最大的元素会“冒”到数组的末尾。
    继续进行下一轮遍历,直到所有元素都在正确的位置上。

3. 示例:

  • 对于数组 [5, 3, 8, 1, 2],第一轮遍历后,最大的数字8会移动到最后,数组变为 [5, 3, 1, 2, 8]。
    接下来的每一轮都会将剩余元素中的最大值移动到已排序部分的末尾,直到数组完全排序为 [1, 2, 3, 5, 8]。

4. 时间复杂度:

  • 平均和最坏情况下的时间复杂度都是 O( n 2 n^{2} n2),其中 n 是数组的长度。这是因为每个元素都要与其他所有元素比较一次。
  • 在最好情况下,如果数组已经排序,只需要进行 n-1 次比较即可完成排序,时间复杂度为 O(n)。

5. 空间复杂度:

  • 冒泡排序是原地排序算法,它不需要额外的存储空间,因此空间复杂度为 O(1)。

6. 稳定性:

  • 冒泡排序是稳定的排序算法,即相等的元素在排序后保持原有的相对顺序。

由于其效率较低,冒泡排序在实际应用中并不常见,但在我们自己学习和理解排序算法原理时很有用。在处理大量数据时,其他更高效的方法如快速排序、归并排序和堆排序更受欢迎。我们先通过简单的java代码来实现这种算法。

二、代码示例

以下代码是冒泡排序从小到大排序的示例

package com.datastructures;

import java.util.Arrays;

/**
 * 冒泡排序算法实现
 * @author hulei
 * @date 2024/5/7 11:41
 */


public class BubbleSort {
    public static void main(String[] args) {
        Integer[] array = {7,3,5,4,8,1,11,15,2};
        System.out.println("冒泡排序前数组:"+Arrays.toString(array));
        bubbleSort(array);
        System.out.println("冒泡排序后数组:"+Arrays.toString(array));
    }


    /**
     * 实现冒泡排序算法,对一个可比较元素数组进行排序。
     *
     * @param array 一个类型为E的数组,其中E必须实现Comparable接口,以便于元素之间的比较。
     *              该数组是待排序的数组。
     * @see java.lang.Comparable
     */
    public static <E extends Comparable<? super E>> void bubbleSort(E[] array){
        int length = array.length;
        // 外层循环控制排序的轮数,每轮确保最大(或最小)的元素位置正确
        for (int i = 0; i < length -1; i++) {
            // 内层循环控制每轮排序中元素的比较,每次比较相邻的两个元素
            for (int j = 0; j < length -1-i; j++) {
                // 如果当前元素大于下一个元素,则交换它们的位置,使得较大的元素逐渐向数组尾部移动
                if(array[j].compareTo(array[j+1])>0){
                    swap(array,j+1,j);
                }
            }
            
        }

    }

    /**
     * 交换数组中两个元素的位置。
     * @param array 要进行交换的数组。
     * @param index1 要交换的第一个元素的索引。
     * @param index2 要交换的第二个元素的索引。
     * @param <E> 数组元素的类型。
     */
    private static <E> void swap(E[] array, int index1, int index2) {
        // 临时变量用于存储第一个元素,以便后续交换
        E temp = array[index1];
        array[index1] = array[index2]; // 将第二个元素的值赋给第一个元素
        array[index2] = temp; // 将之前存储的第一个元素的值赋给第二个元素
    }
}


在这里插入图片描述
代码逻辑比较简单,使用了两层for循环,外层控制循环的论数,n个元素就需要循环排序n轮。
第一轮外循环:
内层循环是相邻元素比较:

  • 第一层内循环从第一个元素A开始比较,相邻比较,如果大于第二个元素,就把第一个元素和第二个元素交换位置。

  • 第二层内循环再把这个A元素(这个元素索引位置已经移动到了第二的位置)和第三个元素比较,如果大于第三个,就把第二个元素A和第三个元素交换位置,交换后元素A移动到了第三的位置。

  • 第三层内循环再把这个元素A(这个元素索引位置已经移动到了第三的位置)和第四个元素比较,如果A小于第四个元素B,则AB不交换,元素A遇到第一个比自己大的元素B

  • 第四层内循环把元素B和第五个元素C比较,如果B小于C,则B遇到第一个比自己大的元素CBC不交换。

  • 第五层内循环把元素C和第六个元素D比较,如果C大于D,则把第五个元素C和第六个元素D交换。

  • 第六层内循环从元素C(元素C在第六的位置)开始和第七个元素E比较



    以此类推直到第一轮内存循环全部结束,最大的元素K被排在最后一位

接着开始第二轮外层循环,内部还是从第一个元素开始与相邻元素比较,比较过并交换的过程同上类似,但是内层循环最终的边界是右边倒数第二个元素,此轮结束后会把第二大的元素M排在右边倒数第二位,即K的前一位




一直到外层循环都结束,通过n轮循环把n个元素按照从小到大的顺序排好了。

三、代码优化

注意以上代码代码其实不是最优代码,因为无论数组是否排序,内层和外层都要进行全部的循环才能完成排序,时间复杂度总是为O( n 2 n^{2} n2),但有一种情况,比如数组已经从小到大排序好了,再进行那么多次循环岂不是浪费?
如果数组已经从小到大排序好了,在第一轮外层循环时就已经能判断出来,判断时会发现下一个元素总是大于前一个,即没有发生过元素交换。
这里提供一个交换标识来判断跳出循环,保证在已排序的情况下不做无谓的循环,优化后代码如下:
bubbleSort方法里加了一个交换标识swapped,第一轮内部循环结束后,swapped为false则说明已排序好,跳出外层循环,其实只进行了第一轮内部循环的n-1次遍历,时间复杂度为O(n-1)

    public static <E extends Comparable<? super E>> void bubbleSort(E[] array){
        int length = array.length;
        boolean swapped; // 标记在某一轮内是否进行了交换
        // 外层循环控制排序的轮数,每轮确保最重(或最轻)的元素位置正确
        for (int i = 0; i < length -1; i++) {
            swapped = false;
            // 内层循环控制每轮排序中元素的比较,每次比较相邻的两个元素
            for (int j = 0; j < length -1-i; j++) {
                // 如果当前元素大于下一个元素,则交换它们的位置,使得较大的元素逐渐向数组尾部移动
                if(array[j].compareTo(array[j+1])>0){
                    swap(array,j+1,j);
                    swapped = true; // 标记已进行交换
                }
            }
            // 如果一轮比较下来没有进行过交换,说明数组已经有序,可以提前结束
            if (!swapped) break;

        }
    }

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

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

相关文章

httpretty,一个神奇的 Python 库!

更多Python学习内容&#xff1a;ipengtao.com 大家好&#xff0c;今天为大家分享一个神奇的 Python 库 - HTTPretty。 Github地址&#xff1a;https://github.com/gabrielfalcao/HTTPretty 在现代软件开发中&#xff0c;API和微服务的测试是确保应用稳定性和功能正确性的关键环…

RAR:Retrieving And Ranking Augmented MLLMs for Visual Recognition

我的博客已全部迁往个人博客站点&#xff1a;oukohou.wang&#xff0c;敬请前往&#xff5e;&#xff5e; paper: RAR:Retrieving And Ranking Augmented MLLMs for Visual Recognitioncodes: https://github.com/Liuziyu77/RAR 一、闲言碎语 RAR&#xff0c;整体动机总结一下…

LeetCode2390从字符串中移除星号

题目描述 给你一个包含若干星号 * 的字符串 s 。在一步操作中&#xff0c;你可以&#xff1a;选中 s 中的一个星号。移除星号 左侧 最近的那个 非星号 字符&#xff0c;并移除该星号自身。返回移除 所有 星号之后的字符串。注意&#xff1a;生成的输入保证总是可以执行题面中描…

JAVA 项目<果园之窗>_完结

目录 1、前言&#xff1a;2、视频展示&#xff1a;3、环境配置&#xff1a;4、工程代码&#xff1a;5、原理&#xff1a;6、原理补充&#xff1a;7、综上&#xff1a; 1、前言&#xff1a; 因为没有足够的时间这个项目用的是别人搭好的框架&#xff0c;在此基础上做调整并根据前…

算法训练营第二十八天 | LeetCode 77 组合(剪枝优化)、LeetCode 216 组合总和III、LeetCode 17 电话号码的字母组合

LeetCode 77 组合&#xff08;剪枝优化&#xff09; 当我们到达某一层&#xff0c;后面的结点数已经不能满足条件时。可以进行剪枝操作。 代码如下&#xff1a; class Solution { private:vector<int> path;vector<vector<int>> res;void backtracking(in…

前端无样式id或者class等来定位标签

目录&#xff1a; 1、使用背景2、代码处理 1、使用背景 客户使用我们产品组件&#xff0c;发现替换文件&#xff0c;每次替换都会新增如下的样式&#xff0c;造就样式错乱&#xff0c;是组件的文件&#xff0c;目前临时处理的话就是替换文件时删除新增的样式&#xff0c;但是发…

机器学习中常用的几种距离——欧式、余弦等

目录 一、欧式距离&#xff08;L2距离&#xff09;二、曼哈顿距离&#xff08;L1距离&#xff09;三、汉明距离四、余弦相似度 一、欧式距离&#xff08;L2距离&#xff09; &#xff08;1&#xff09;二维空间的距离公式&#xff08;三维空间的在这个基础上类推&#xff09;&…

Spring AI项目Open AI对话接口开发指导

文章目录 创建Spring AI项目配置项目pom、application文件controller接口开发接口测试 创建Spring AI项目 打开IDEA创建一个新的spring boot项目&#xff0c;填写项目名称和位置&#xff0c;类型选择maven&#xff0c;组、工件、软件包名称可以自定义&#xff0c;JDK选择17即可…

IDC:2023年中国IT安全软件市场同比增长4.7%

IDC最新发布的《中国IT安全软件市场跟踪报告&#xff0c;2023H2》显示&#xff0c;2023年下半年中国IT安全软件市场厂商整体收入约为169.8亿人民币&#xff08;约合23.5亿元美元&#xff09;&#xff0c;同比上升2.7%。结合全年数据&#xff0c;2023全年中国IT安全软件市场规模…

学习Uni-app开发小程序Day11

今天是学习的第11天&#xff0c;今天学习了组件的生命周期&#xff0c;这里的生命周期&#xff0c;主要是学习uni-app的组件生命周期&#xff0c;虽然vue也有&#xff0c;但主要还是学习uni-app的。1. onLoad 监听页面加载&#xff0c;该钩子被调用时&#xff0c;响应式数据、计…

Python新手注意:避免常见错误,学会‘/’和‘\’的正确使用

Python 编程语言中的正反斜杠符号&#xff08;‘/’和‘\’&#xff09;是非常基础但又极其重要的元素&#xff0c;它们在不同的场合下扮演着不同的角色。了解这两个符号的意义和用法&#xff0c;对于编写清晰、有效的代码至关重要。 基础概念 正斜杠&#xff08;‘/’&#…

Image to Music V2 :只需上传一张照片,自动转换成与图片内容匹配的音频!

前言 我们之前肯定已经见过了很多文本生成图片、文本生成声音以及AI翻唱歌曲 等多种AI产品&#xff08;模型&#xff09;。 其实音乐和图片从某种意义上来说都是艺术创作的一种形式&#xff0c;它们可以相互配合&#xff0c;共同呈现出一种更加丰富、感性的表达方式。 将图片…

vue+vant项目0-1快速发布到--钉钉应用

uniapp开发笔记----vue开发项目配置钉钉应用 一、 vuevant开发项目1. 自定义vuevant项目或者已经有的旧项目1. 自定义vuevant项目1. 创建vue项目2. 安装依赖3. 引入所有组件4. 使用一个组件/效果和代码如下&#xff1a; 2. git官网仓库&#xff0c;直接拉默认dome代码3. 打包项…

优思学院:精益六西格玛如何影响企业文化?

精益六西格玛&#xff08;Lean Six Sigma&#xff09;是一种在优化生产过程、提高效率、减少浪费的管理方法论。其影响远不止于生产线或质量控制部门&#xff0c;实际上&#xff0c;精益六西格玛的实施可以深刻影响企业文化的各个层面&#xff0c;從而令企業獲得真正最大的成功…

游戏中的设计模式一

游戏开发是一个快速迭代的过程&#xff0c;代码复杂度也很高&#xff0c;借助于设计模式&#xff0c;可以帮助我们降低复杂度&#xff0c;降低系统间的耦合&#xff0c;从而高效高质的做出交付。 最近读了这本书&#xff1a;《游戏编程模式》[1]&#xff0c;很受启发&#xff…

AC/DC电源模块的可靠性设计与测试方法

BOSHIDA AC/DC电源模块的可靠性设计与测试方法 AC/DC电源模块是一种将交流电能转换为直流电能的设备&#xff0c;广泛应用于各种电子设备中&#xff0c;如电脑、手机充电器、显示器等。由于其关系到设备的供电稳定性和安全性&#xff0c;因此可靠性设计和测试是非常重要的。下…

AI绘画Stable Diffusion换脸插件ReActor 不香了,新一代换脸神器 InstantID!

前 言 之前我介绍了 SD 中的一款换脸插件 ReActor&#xff0c;虽然好使&#xff0c;但是安装还是有些许麻烦的。 今天给小伙伴们介绍一款新型的换脸插件&#xff1a;InstantID&#xff0c;主要是使用 ControlNet 和 IP-Adapter 的组合来控制扩散过程中的面部特征。 一句话&a…

「JavaEE」多线程案例分析2:实现定时器

&#x1f387;个人主页&#xff1a;Ice_Sugar_7 &#x1f387;所属专栏&#xff1a;JavaEE &#x1f387;欢迎点赞收藏加关注哦&#xff01; 实现定时器 &#x1f349;简介&#x1f349;模拟实现定时器 &#x1f349;简介 定时器类似一个闹钟&#xff0c;时间到了之后就会执行…

【全开源】JAVA国际版多语言语聊大厅语音聊天APP系统源码

JAVA国际版多语言语聊大厅语音聊天APP系统源码——深度解析市场需求&#xff0c;打造全球化语音社交平台 随着全球化的推进和移动互联网的普及&#xff0c;人们对于语音聊天的需求日益增长。尤其是在国际交流日益频繁的今天&#xff0c;一个支持多语言、覆盖全球用户的语音聊天…

分布式搜索-elaticsearch基础 概念

什么是elaticsearch: 倒排索引&#xff1a;就是将要查询的内容分成一个个词条&#xff0c;在将词条文档id存入&#xff0c;词条是唯一的。 文档词条总结: mysql和Elasticsearch概念对比: 架构: 基本概念总结: