冒泡排序

相关概念

  • 稳定:如果 a 原本在 b 前面,而 a = b,排序之后 a 任在 b 前面
  • 不稳定:如果 a 原本在 b 前面,a = b,排序之后 a 可能会出现在 b 后面
  • 时间复杂度:对排序数组总的操作次
  • 空间复杂度:算法在计算机内执行时所需存储空间的度量

冒泡排序(BUBBLE SORT)

原理

比较两个相邻元素,将值大的元素交换至右端。

动态效果示意图

在这里插入图片描述

思路
1. 依次比较两个元素,将小数放在前面,大数放在后面。即在第一趟:首先比较第一个和第二个数,将小数放在前面,大数放在后面。然后比较第二个和第三个数,小数放前,大数放后;直至比较到最后两个数,小数放前,大数放后。
2. 第一趟比较完成后,最后一个数一定是数组中最大的那个数,所以第二趟比较的时候最后一个数不参与。
3. 依次类推,每一趟比较次数减1。
  • 举例说明
    6, 3, 8,2, 9,1
    第一趟排序:
    第一次排序:6和3比较,6大于3,交换位置:3, 6, 8,2, 9,1
    第二次排序:6和8比较,6小于8,不交换位置:3, 6, 8,2, 9,1
    第三次排序:8和2比较,8大于2,交换位置:3, 6, 2,8, 9,1
    第四次排序:8和9比较,8小于9,不交换位置:3, 6, 2,8, 9,1
    第五次排序:9和1比较,9大于1,交换位置:3, 6, 2,8, 1,9
    第一趟进行了五次比较,排序结果:3, 6, 2,8, 1,9
    ========================================================================
    第二趟排序:
    第一次排序:3和6比较,3小于6,不交换位置:3, 6, 2,8, 1,9
    第二次排序:6和2比较,6大于2,交换位置:3, 2, 6,8, 1,9
    第三次排序:6和8比较,6小于8,不交换位置:3, 2, 6,8, 1,9
    第四次排序:8和1比较,8大于1,交换位置:3, 2, 6,1, 8,9
    第二趟总共进行了四次比较,排序结果:3, 2, 6,1, 8,9
    ========================================================================
    。。。。。。
    。。。。。。
    。。。。。。
    最终结果:1,2,3,6,8,9
    ========================================================================
    由此可见,N 个数字要完成排序,总共要进行 N - 1 趟排序,每 i 趟的排序次数为(N - i)次,所以可以使用双重循环语句,外层控制循环多少趟,内层控制每一趟循环的次数。
/*
时间复杂度分析:
1、这是没有经过优化的最初级冒泡排序程序
2、由程序可以看出,比较次数是不受原始数据的是否有序影响的,循环的次数是固定的
3、其外层循环 N-1 次,内层最多走 N-1 次,最少走 1 次,一共比较 (N-1)+(N-2)+...+2+1,共 (N-1)N/2 次,时间复杂度为 O(n^2) 
*/
public static void bubbleSort(int[] arr){
        //冒泡排序算法
        for (int i = 0; i < arr.length-1; i++) { //外层循环控制趟数
            for (int j = 0; j < arr.length-1-i; j++) { //内层循环控制每一趟排序的次数
                if(arr[j] > arr[j+1]){
                    //交换arr[j] 和 arr[j+1]
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
    }
冒泡排序的优点

每进行一趟排序,就会少比较一次,因为每进行一趟排序就会找出一个较大的值,这样在一定程度上减少了算法的量。
用时间复杂度来说:
对于没有改进的冒泡初级程序,比较次数是不受原始数据的是否有序影响的,循环的次数是固定的,即 (N-1)N/2 ,时间复杂度为 O(n^2) 。

改进冒泡排序算法的性能

改进冒泡排序算法的思想是:假设第 n 遍数据已经排好序不需要改变了,扫描第 n+1 次的时候只是比较而没有交换,这是就可以跳出循环了,因为这是说明已经排好序了。因此可以设置一个标识变量 flag ,在每一遍扫描之前将 flag 设为 false,如果有数据交换则设为 true,扫描完一遍之后看 flag 的值,如果 flag 为 false 说明这遍已经没有数据交换了,数据已经是有序的了,就跳出循环。

public static void bubbleSort2(int[] arr){
        for (int i = 0; i < arr.length-1; i++) { //外层循环控制趟数
            //flag 标志用于指示这一趟的循环是否发生了交换
            boolean flag = false;
            for (int j = 0; j < arr.length-1-i; j++) { //内层循环控制每一趟排序的次数
                if(arr[j] > arr[j+1]){
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                    //flag 为 true 说明发生了交换操作
                    flag = true;
                }
            }
            if(flag == false)
                break;
        }
    }
改进后的冒泡排序的时间复杂度分析

因为加了标志位 flag 来判断在一趟循环之后是否发生了交换,如果在一趟排序之后没有发生交换则说明数组已经是排好序的了,则不需要再进行循环了,退出循环即可。所以,对于一个有序数组,使用冒泡排序的时间复杂度为 O(n)。在最坏的情况下,即数组是逆序的,就像没有改进过的冒泡排序一样了,需要执行 (N-1)N/2 次的比较,这时的时间复杂度为 O(n^2)。
综合来看,改进过的冒泡排序的时间复杂度为 O(n^2)。

冒泡排序改进

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值