冒泡排序及其优化

文章目录

    • 冒泡排序算法
      • 排序流程
    • 动图
    • 算法分析
    • java代码
    • 冒泡排序优化
      • 添加标识优化冒泡
      • 记录最后交换元素位置优化排序
      • 鸡尾酒排序

冒泡排序算法

冒泡排序属于交换排序,通过元素间的比较和交换位置来达到排序目的。

冒泡排序的每一轮只把一个元素冒泡到数列的一端,从序列左边开始比较相邻两个数字的大小,根据结果交换两个数字的位置。

排序流程

  1. 比较相邻的元素,如果第一个比第二个大,就交换它们两个;
  2. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数;
  3. 针对所有的元素重复以上的步骤,除了最后一个;
  4. 重复步骤1~3,直到排序完成。

动图

算法分析

优点:稳定;

缺点:慢,每次只能移动两个相邻的数据。

最佳情况:O(n)
最差情况:O(n^2)
平均情况:O(n^2)
空间复杂度:O(1)
比较次数:(n-1) + (n-2) + … + 1 = n^2/2

java代码

public <T extends Comparable<T>> T[] sort(T[] array) {
    int len = array.length;
    for (int i = 0; i < len - 1; i++) {
        System.out.format("第%d遍:\n", i + 1);

        for (int j = 0; j < len - i - 1; j++) {
            if(less(array[j + 1], array[j])) {
                swap(array, j, j + 1);
            }
            System.out.format("第%d遍的第%d次交换:", i + 1, j + 1);
            print(array);
        }
        System.out.println();
    }

    return array;
}

冒泡排序优化

添加标识优化冒泡

当我们输入数组:[1, 3, 6, 2, 9],通过上面程序可以看到输出:

第1遍:
第1遍的第1次交换:[1, 3, 6, 2, 9]
第1遍的第2次交换:[1, 3, 6, 2, 9]
第1遍的第3次交换:[1, 3, 2, 6, 9]
第1遍的第4次交换:[1, 3, 2, ***6, 9***]

第2遍:
第2遍的第1次交换:[***1, 3***, 2, 6, 9]
第2遍的第2次交换:[1, ***2, 3***, 6, 9]
第2遍的第3次交换:[1, 2, ***3, 6***, 9]

第3遍:
第3遍的第1次交换:[***1, 2***, 3, 6, 9]
第3遍的第2次交换:[1, ***2, 3***, 6, 9]

第4遍:
第4遍的第1次交换:[***1, 2***, 3, 6, 9]

由上看出,经过第二遍后,数组已经有序了,但算法还是继续执行到了第4遍才完成。

因此,可以通过添加一个标记,标识数列已经有序了,然后跳出循环。

代码如下:

public <T extends Comparable<T>> T[] sort(T[] array) {
    int len = array.length;
    for (int i = 0; i < len - 1; i++) {
        System.out.format("第%d遍:\n", i + 1);
        boolean isSorted = true;
        for (int j = 0; j < len - i - 1; j++) {
            if(less(array[j + 1], array[j])) {
                swap(array, j, j + 1);
                // 有元素位置交换,序列不是有序的
                isSorted = false;
            }
            System.out.format("第%d遍的第%d次交换:", i + 1, j + 1);
            print(array);
        }
        System.out.println();
        if(isSorted) {
            break;
        }
    }

    return array;
}

交换过程如下:

第1遍:
第1遍的第1次交换:[1, 3, 6, 2, 9]
第1遍的第2次交换:[1, 3, 6, 2, 9]
第1遍的第3次交换:[1, 3, 2, 6, 9]
第1遍的第4次交换:[1, 3, 2, 6, 9]

第2遍:
第2遍的第1次交换:[1, 3, 2, 6, 9]
第2遍的第2次交换:[1, 2, 3, 6, 9]
第2遍的第3次交换:[1, 2, 3, 6, 9]

第3遍:
第3遍的第1次交换:[1, 2, 3, 6, 9]
第3遍的第2次交换:[1, 2, 3, 6, 9]

从上面的过程可以发现,是有优化了,但还是会有问题。第二遍开始已经有序了,但算法没发现。

记录最后交换元素位置优化排序

上面问题根本原因是算法并不知道数列有序去的开始位置,

为解决这个问题,我们可以记录最后一次元素交换的索引,这个索引之后的序列是有序的。

代码:

public <T extends Comparable<T>> T[] sort(T[] array) {
    int len = array.length;
    int rightIndex = len - 1;
    int lastSwapIndex = 0;
    for (int i = 0; i < len - 1; i++) {
        System.out.format("第%d遍:\n", i + 1);
        boolean isSorted = true;
        for (int j = 0; j < rightIndex; j++) {
            if(less(array[j + 1], array[j])) {
                swap(array, j, j + 1);
                // 有元素位置交换,序列不是有序的
                isSorted = false;
                lastSwapIndex = j;
            }
            System.out.format("第%d遍的第%d次交换:", i + 1, j + 1);
            print(array);
        }

        System.out.println();
        rightIndex = lastSwapIndex;
        if(isSorted) {
            break;
        }
    }

    return array;
}

鸡尾酒排序

鸡尾酒排序属于冒泡排序的一种升级。

不同于冒泡排序的每一轮都从左到右进行比较元素,进行单向的位置交换,鸡尾酒排序的元素比较和交换都是双向的。

public <T extends Comparable<T>> T[] sort(T[] array) {
    int len = array.length;
    for (int i = 0; i < len/2; i++) {
        System.out.format("第%d遍:\n", i + 1);
        boolean isSorted = true;
        for (int j = i; j < len - i - 1; j++) {
            if(less(array[j + 1], array[j])) {
                swap(array, j, j + 1);
                // 有元素位置交换,序列不是有序的
                isSorted = false;
            }
            System.out.format("第%d遍的第%d次交换:", i + 1, j + 1);
            print(array);
        }

        if(isSorted) {
            break;
        }

        isSorted = true;
        for (int j = len -i  - 1; j > i; j--) {
            if(less(array[j], array[j - 1])) {
                swap(array, j, j - 1);
                // 有元素位置交换,序列不是有序的
                isSorted = false;
            }
            System.out.format("第%d遍的第%d次交换:", i + 1, j + 1);
            print(array);
        }
        System.out.println();
        if(isSorted) {
            break;
        }
    }

    return array;
}

你可能感兴趣的:(算法与数据结构)