首页 > 编程语言 >【基础算法】排序算法 —— 冒泡排序

【基础算法】排序算法 —— 冒泡排序

时间:2023-10-04 20:44:48浏览次数:34  
标签:arr 复杂度 交换 冒泡排序 算法 冒泡 排序

一、算法原理

冒泡排序只会操作相邻的两个数据。每次冒泡操作都会对相邻的两个元素进行比较,如果不满足大小关系要求,就进行交换。一次冒泡会让至少一个元素移动到它应该在的位置,重复 n 次,就完成了 n 个数据的排序。

 

示例:使用冒泡排序对数组 arr = [4,5,6,3,2,1] 从小到大排序。

第1次冒泡:

第2次冒泡:

第3次冒泡:

第4次冒泡:

第5次冒泡:

第6次冒泡:

 

冒泡过程回顾

 

二、冒泡排序算法优化

思路:当某次冒泡操作没有数据交换时,说明数组已经完全有序,不用再进行后续的冒泡操作。

 

示例:使用冒泡排序对数组 arr = [3,5,4,1,2,6] 从小到大排序。

第1次冒泡:

第2次冒泡:

第3次冒泡:

第4次冒泡:

第4次冒泡操作无数据交换,说明数组已经完全有序,不用再进行后续的冒泡操作。

 

三、代码实现

/**
 * 冒泡排序:时间复杂度 O(n^2),空间复杂度 O(1),稳定
 *
 * @param arr 待排序数组
 */
public static void bubbleSort(int[] arr) {
    if (arr == null || arr.length < 2) {
        return;
    }

    boolean isSwap = false;
    for (int i = 0, len = arr.length; i < len - 1; i++) { // 冒泡操作的次数
        for (int j = 0; j < len - 1 - i; j++) { // 每次冒泡比较的元素
            if (arr[j] > arr[j + 1]) {
                swap(arr, j, j + 1);
                isSwap = true;
            }
        }
        // 优化:没有交换代表数组已经完全有序
        if (!isSwap) {
            return;
        }
    }
}

private static void swap(int[] arr, int i, int j) {
    if (i == j) {
        return;
    }
    arr[i] = arr[i] ^ arr[j];
    arr[j] = arr[i] ^ arr[j];
    arr[i] = arr[i] ^ arr[j];
}

 

四、算法评价

4.1 时间复杂度

最好时间复杂度:O(n)

最好情况下,要排序的数组已经是有序的,只需要进行一次冒泡操作,就可以结束了,所以最好情况时间复杂度是 O(n)。

最坏时间复杂度:O(n2)

最坏情况下,要排序的数组刚好是倒序排列的,需要进行 n 次冒泡操作,所以最坏情况时间复杂度为 O(n2)。

平均时间复杂度:O(n2)

平均时间复杂度就是加权平均期望时间复杂度,分析的时候要结合概率论的知识。对于包含 n 个数据的数组,这 n 个数据就有 n! 种排列方式。不同的排列方式,冒泡排序执行的时间肯定是不同的。比如我们前面举的那两个例子,其中一个要进行 6 次冒泡,而另一个只需要 4 次。如果用概率论方法定量分析平均时间复杂度,涉及的数学推理和计算会很复杂。这里我们通过“有序度”和“逆序度”来进行分析。

冒泡排序包含两个操作原子:比较交换。每交换一次,有序度就加 1。不管算法怎么改进,交换的总次数是确定的,即为逆序度,也就是 n*(n-1)/2 - 初始有序度。第1个示例中的数组就是 15 – 3 = 12,要进行 12 次交换操作。

对于包含 n 个数据的数组进行冒泡排序,平均交换次数是多少呢?最坏情况下,初始状态的有序度是 0,所以要进行 n*(n-1)/2 次交换。最好情况下,初始状态的有序度是 n*(n-1)/2,就不需要进行交换。我们可以取个中间值 n*(n-1)/4,来表示初始有序度既不是很高也不是很低的平均情况。换句话说,平均情况下,需要 n*(n-1)/4 次交换操作,比较操作肯定要比交换操作多,而复杂度的上限是 O(n2),所以平均情况下的时间复杂度就是 O(n2)。这个平均时间复杂度推导过程并不严谨,但是很实用,毕竟概率论的定量分析太复杂,不太好理解。

 

4.2 空间复杂度

冒泡过程只涉及相邻元素的比较和交换操作,只需要常量级的临时空间,所以它的空间复杂度为 O(1),是一个原地排序算法。

 

4.3 稳定性

冒泡排序中,只有交换才会改变两个元素的前后顺序。当相邻的两个元素大小相等时,我们不做交换,所以相同大小的数据在排序前后不会改变顺序,这样就可以保证冒泡排序是稳定的排序算法。

 

标签:arr,复杂度,交换,冒泡排序,算法,冒泡,排序
From: https://www.cnblogs.com/luwei0424/p/17742718.html

相关文章

  • 稳定婚姻问题(Gale-Shapley算法)
    前言今天duck、香饽饽老板和彬彬一起出了个模拟赛,赛时T2想到了跟正解很接近的做法,但最后还是打挂了then喜提0pts,后面duck讲题的时候才知道是稳定婚姻板题。看完证明之后觉得很妙,遂开坑。只是简单整理,图一乐子吧算是。说是稳定婚姻问题,但其实我觉得更合适的叫法是属性稳定分......
  • 【基础算法】排序算法
    一、排序算法简介排序是对批量数据按照一定的顺序进行排列的操作。1.1学习排序算法的要点算法原理、代码实现、评价算法优劣。1.2评价排序算法的优劣排序算法的优劣可以从以下3个方面进行评价:时间性能:最好、最坏、平均时间复杂度;内存占用:是否原地排序,原地排序算法,......
  • eslint airbnb React18+typescript 依赖循环、import自动排序分组
    eslint终极规范爱彼迎eslint-config-airbnb请先阅读完下以下链接在来配置代码规范之什么是eslint,为什么要使用eslinteslint的配置项过多,针对js、ts、vue、jsx、tsx等等不同的规则,小公司或者个人项目可以使用成熟的eslint社区规范,如airbnb、standard、goole等。这里我们介绍......
  • C/C++学习 -- 分组加密算法(DES算法)
    数据加密标准(DataEncryptionStandard,DES)是一种对称密钥加密算法,是信息安全领域的经典之作。本文将深入探讨DES算法的概述、特点、原理,以及提供C语言和C++语言实现DES算法的代码案例。一、DES算法概述DES算法是一种对称密钥加密算法,由IBM于1977年开发并于1977年被美国国家标准局(NI......
  • 02 快速排序(快排)
    #include"stdio.h"voidQuickSort(int*array,intlow,intheight){inti,j,tmp;//两个哨兵,和开头的元素下标inttemp;i=low;j=height;tmp=array[low];if(i>j)//如果下标i大于下标j,函数结束运行{return;}......
  • 视频融合/监控汇聚平台EasyCVR人形检测算法应用汇总
    安防视频监控平台EasyCVR是一个具有强大拓展性、灵活的视频能力和轻便部署的平台。它支持多种主流标准协议,包括国标GB28181、RTSP/Onvif、RTMP等,还可以支持厂家的私有协议和SDK接入,例如海康Ehome、海大宇等设备的SDK。该平台不仅拥有传统安防视频监控的功能,还具备接入AI智能分析的......
  • 排序算法
    在线验证算法排序数组算法实现1.快排思路树的前序遍历。每次选取一个数作基准值,将小于基准值的数放在左边,大于基准值的数放在右边。遍历左子树及右子树,直到只有1个数为止。实现classQuickSort{publicstaticvoidsort(int[]nums){shuffle(nums);......
  • 归并排序算法详解
    算法介绍引用百度百科的介绍。归并排序(MergeSort)是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(DivideandConquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表......
  • 算法:线段树
    算法:线段树哦吼!终于来学线段树啦~~拖了好久都没有敢学,主要是基础知识点不熟,代码能力太弱。但是现在已经是时候了。来看:线段树(SegmentTree)几乎是算法竞赛最常用的数据结构了,它主要用于维护区间信息(要求满足结合律)。与树状数组相比,它可以实现\(O(log⁡\n)\)的区间修改,......
  • 文心一言 VS 讯飞星火 VS chatgpt (105)-- 算法导论10.1 3题
    三、用go语言,仿照图10-2,画图表示依次执行操作ENQUEUE(Q,4)、ENQUEUE(Q,1)、ENQUEUE(Q,3)、DEQUEUE(Q)、ENQUEUE(Q,8)和DEQUEUE(Q)每一步的结果,队列初始为空,存储于数组Q[1..6]中。文心一言:在这个问题中,我们尝试使用Go语言来模拟队列的操作,并且展示每一步的结果。首先,我们需要定......