排序算法 - 冒泡排序

本文详细介绍了冒泡排序的基本思想、工作原理,提供了Java代码示例,并对其时间复杂度、空间复杂度以及稳定性进行了分析。同时,针对冒泡排序效率低的问题,提出了优化方法,并对比了其与快速排序、归并排序等高效排序算法的应用场景。
摘要由CSDN通过智能技术生成

冒泡排序

介绍

冒泡排序(Bubble Sort)是一种基础的排序算法。它的基本思想是通过比较相邻的两个元素,将较大的元素交换到后面,从而将最大的元素冒泡到数组的末尾。这个过程重复多次,直到数组有序为止。这个算法的名字由来是因为越大的元素会经由交换慢慢 “浮” 到数组的顶端。

原理

冒泡排序的原理可以用下图来演示,假设要对数组 [5, 3, 4, 1, 2] 进行升序排序:

image-20240314164122156

第一趟排序:

比较第 1 和第 2 个元素,5 > 3,交换位置,得到 [3, 5, 4, 1, 2]

image-20240314164839964

比较第 2 和第 3 个元素,5 > 4,交换位置,得到 [3, 4, 5, 1, 2]

image-20240314165349138

比较第 3 和第 4 个元素,5 > 1,交换位置,得到 [3, 4, 1, 5, 2]

image-20240314214930053

比较第 4 和第 5 个元素,5 > 2,交换位置,得到 [3, 4, 1, 2, 5]

image-20240314215357590

第一趟排序结束后,最大的元素已经移到了最后一个位置。

image-20240314215658670

第二趟排序:

比较第 1 和第 2 个元素,3 < 4,不交换位置,得到 [3, 4, 1, 2, 5]

image-20240314220157207

比较第 2 和第 3 个元素,4 > 1,交换位置,得到 [3, 1, 4, 2, 5]

image-20240314220420612

比较第 3 和第 4 个元素,4 > 2,交换位置,得到 [3, 1, 2, 4, 5]

image-20240314221109766

比较第 4 和第 5 个元素,4 < 5,不交换位置,得到 [3, 1, 2, 4, 5]

image-20240314221342981

第二趟排序结束后,次大的元素已经移到了倒数第二个位置。

依此类推,经过 n -1 趟排序后,数组就变成了有序的。

完整的动态效果如下:

在这里插入图片描述

代码

冒泡排序的 Java 代码实现如下:

/**
 * 冒泡排序的实现
 *
 * @author 孤诣
 */
public class BubbleSort {
    public static void main(String[] args) {
        // 数据准备
        int[] dataArray = {7, 0, 9, 5, 6, 8, 4, 3, 1, 2};
        System.out.println("排序前: " + Arrays.toString(dataArray));

        // 排序
        bubbleSort(dataArray);
        System.out.println("排序后: " + Arrays.toString(dataArray));
    }

    /**
     * 冒泡排序算法的实现
     *
     * @param source - 源数据
     */
    public static void bubbleSort(int[] source) {
        // 数组中元素的个数
        int itemNum = source.length;

        // 外层循环, 决定排序次数
        for (int i = 0; i < itemNum; i++) {
            // 内层循环, 决定比较次数
            for (int j = 0; j < itemNum - 1; j++) {
                if (source[j] > source[j + 1]) {
                    swap(source, j, (j + 1));
                }
            }
        }
    }

    /**
     * 将一个数组的两个元素位置互换
     *
     * @param source - 源数组
     * @param i      - 第一个元素
     * @param j      - 第二个元素
     */
    private static void swap(int[] source, int i, int j) {
        int temp = source[i];
        source[i] = source[j];
        source[j] = temp;
    }
}

通过【原理】部分的的图解我们可以发现,在进行第 i 轮的排序时,从倒数第(i-1)位置开始,元素就已经是有序的了,而上面的代码依然会将未排序的元素与排序完成的部分进行比较,直到全部比较完成。

因此,我们可以对上面的代码进行优化,使其在排序过程中可以忽略排序完成的部分。

具体做法是记录未排序元素个数 disorderItemNum,每轮排序只需要对数组前 disorderItemNum 个元素比较即可。每完成一轮排序,未排序元素个数将会减一。优化后的代码如下:

/**
 * 冒泡排序算法的实现 - 优化
 *
 * @param source - 源数据
 */
public static void bubbleSort(int[] source) {
    // 数组中未排序元素的个数, 这些元素总是位于已排序元素的前面
    int disorderItemNum = source.length;

    // 外层循环, 决定排序次数
    while (disorderItemNum > 0) {
        // 内层循环, 决定比较次数
        for (int i = 0; i < disorderItemNum - 1; i++) {
            if (source[i] > source[i + 1]) {
                swap(source, i, (i + 1));
            }
        }
        // 更新数组中未排序元素的个数
        disorderItemNum--;
    }
}

评估

时间复杂度:

  • 最好情况:O(n)
  • 最坏情况:O(n^2)
  • 平均时间复杂度:O(n^2)

空间复杂度:O(1)

稳定性:稳定。

补充 - 排序算法的稳定性

判断一个排序算法是否稳定的方法是检查在排序过程中相同值的元素是否保持其原有的顺序关系。具体来说,一个稳定的排序算法在排序过程中,如果两个相等的元素在数组中相邻,那么在排序之后,这两个元素仍然相邻,并且顺序不会改变。

举个例子,对数组 [3(1), 2, 4,3(2), 1] 进行排序:

  • 稳定的排序算法:[1, 2, 3(1), 3(2), 4]

  • 不稳定的排序算法:[1, 2, 3(2), 3(1), 4]

冒泡排序的优点是排序思想简单,代码实现容易。但是,它的效率相对较低,不适合对大数据集进行排序。在实际应用中,通常选择更高效的排序算法,如快速排序、归并排序等,这些算法,后续将会逐一介绍。

  • 24
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值