欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

排序算法(一)-冒泡排序

程序员文章站 2022-03-24 13:53:22
...

0. 原理

  • 临近的数字两两比较,按照从小到大或者从大到小的顺序进行交换。
  • 每一趟会将最大或者最小的数字放到最终结果的位置
  • 重复操作直到倒数第二位

对[2, 8, 1, 5, 3]这个数组排序,完整流程如下

round 1 start
2 8 1 5 3  (exchange data: 3 <-> 5)  2 8 1 3 5 
2 8 1 3 5  (exchange data: 1 <-> 8)  2 1 8 3 5 
2 1 8 3 5  (exchange data: 1 <-> 2)  1 2 8 3 5 
round 1 finish
round 2 start
1 2 8 3 5  (exchange data: 3 <-> 8)  1 2 3 8 5 
round 2 finish
round 3 start
1 2 3 8 5  (exchange data: 5 <-> 8)  1 2 3 5 8 
round 3 finish
round 4 start
round 4 finish

可见第一趟将最小的1放到了第一位
为什么叫冒泡排序呢?因为上面两两交换的过程每一趟都将最小的值放到了最顶端,很像气泡上升到顶部的过程。

1. 实现

关键代码实现如下:

@Override
public int[] sort(int[] data) {
    if (data == null || data.length <= 1) {
        return data;
    }

    for (int i = 0; i < data.length - 1; i++) {
        for (int j = data.length - 1; j > i; j--) {
            if (data[j] < data[j - 1]) {
                swap(data, j, j - 1);
            }
        }
    }

    return data;
}

具体实现可查看:

GitHub/BubleSort.java

2. 复杂度分析

从代码和原理可以看出,外层循环需要n-1次,内层循环需要n-i次,比较一次,数据操作三次。因此最坏的情况应该是整个序列时逆向的,时间复杂度为O(n²),最好的情况是序列时正序的一次扫描即可,时间复杂度为O(n)。平均时间复杂度为O(n²)。由于不需要额外空间,空间复杂度为O(1)

3. 优化

3.1 优化点一

如果某一趟没有发生过一次交换,则说明该数组已经有序,可以直接停止循环。只要加一个标识变量就可以实现。

3.2 优化点二

使用一个标识变量记录下最后一个发生交换的位置,则可以说明前面没有发生交换的序列已经有序,所以内部循环的终结点可以用这个值来作为结束点,也就是上面代码中的i值。在内部循环结束后i=changFlag就是这个作用。

两个优化点写入代码后如下:

@Override
public int[] sort(int[] data) {
    if (data == null || data.length <= 1) {
        return data;
    }

    //标识是否已经有序
    boolean isChanged;
    //标识最后一个发生变化的位置
    int changFlag = 0;

    for (int i = 0; i < data.length - 1; i++) {
        isChanged = false;
        System.out.println("round " + (i + 1) + " start");
        for (int j = data.length - 1; j > i; j--) {
            if (data[j] < data[j - 1]) {
                swap(data, j, j - 1);
                isChanged = true;
                changFlag = j - 1;
            }
        }
        //i直接设置为最后一次的交换
        i = changFlag;
        //如果没有改变,则证明序列已经有序
        if (!isChanged) {
            System.out.println("no exchange, break out loop");
            break;
        }
        System.out.println("round " + (i + 1) + " finish");
    }

    return data;
}

具体实现可查看:

GitHub/BubleSort.java