冒泡排序及优化

478 阅读3分钟

冒泡排序及优化

选择排序(SelectionSort)

堆排序(HeapSort)

插入排序及优化

升序排序

核心步骤

  1. 从头开始比较每一对相邻元素,如果第一个比第二个大,就交换位置。-->经过一轮后最大的元素就到最后了。

  2. 对于最后一位之前的元素执行重复步骤1,就能对所有元素进行升序排列。

步骤一:

 	//比较,筛选出当前列最大的数放到最后
            for (int start = 1; start < end; start++) {
                if (data[start] < data[start - 1]) {
                    swap(data, start, start - 1);
                }
            }

步骤二:

 	//从后面逐步减少遍历个数
        for (int end = data.length; end > 1; end--) {
            步骤一
        }

全部代码:

public class BubbleSort {

    public static void main(String[] args) {
        int[] array = {10, 2, 6, 1, 7};
        sort(array);

        for (int i1 : array) {
            System.out.println(i1);
        }
    }

    private static void sort(int[] data) {
        //从后面逐步减少遍历个数
        for (int end = data.length; end > 1; end--) {
            //比较,筛选出当前列最大的数放到最后
            for (int start = 1; start < end; start++) {
                if (data[start] < data[start - 1]) {
                    swap(data, start, start - 1);
                }
            }
        }
    }

    private static void swap(int[] data, int first, int end) {
        int temp = data[first];
        data[first] = data[end];
        data[end] = temp;
    }


}

优化一

如果拿到的元素就是有序的。可以提前终止排序。

其实每一趟扫描之后,就能确定元素是否有序。如下:

  if (data[start] < data[start - 1]) {
          swap(data, start, start - 1);
     }

如果swap一次都没执行,说明当前元素已经是有序的了。

所以我们可以加一个标识,用来记录当前遍历是否有序,此时就没必要进行下一次的遍历了。

//优化后的sort
private static void sort2(int[] data) {
        //从后面逐步减少遍历个数
        for (int end = data.length; end > 1; end--) {
            boolean sorted = true;
            //比较,筛选出当前列最大的数放到最后
            for (int start = 1; start < end; start++) {
                if (data[start] < data[start - 1]) {
                    swap(data, start, start - 1);
                    //序列无序的
                    sorted = false;
                }
            }
            //当前序列已经是有序的了,没必要再遍历
            if (sorted) {
                break;
            }
        }
    }

**Note:**只是针对数据是提前有序的有优化效果。如果数据完全无序,那么由于代码行数多了,甚至会导致时间还长了点。

测试代码:

    public static void main(String[] args) {
        //获取一个升序数组
        Integer[] array = Integers.ascOrder( 1, 100000);
        Integer[] array1 = Integers.copy(array);
        assert array != null;
        Times.test("冒泡排序", () -> {
            sort(array);
        });
        Times.test("冒泡排序2", () -> {
            sortPro(array1);
        });
    }

输出:

【冒泡排序】
开始:13:48:10.554
结束:13:48:14.159
耗时:3.605秒
-------------------------------------
【冒泡排序2】
开始:13:48:14.161
结束:13:48:14.165
耗时:0.004秒
-------------------------------------

Process finished with exit code 0

优化二

尾部局部有序

可以记录最后一次交换的位置,最后一次交换位置后续的元素就是有序的。

比如: 3,4,1,5,7,10

其中最后一次是1的位置,他后面的位置就是有序的,没有必要再比较了。

所以下一轮再进来的时候只需要将前面无序的再扫描一遍就行

  private static void sort3(Integer[] data) {
        //从后面逐步减少遍历个数
        for (int end = array.length-1; end > 0; end--) {
            //sortIndex最后会复制给end,
            //sortIndex需要考虑完全有序的时候,end会就是初始值,
            //此时要退出循环,所以可以设置1,0等让下次循环条件不符合。
            int sortIndex = 1;
            //比较,筛选出当前列最大的数放到最后
            for (int start = 1; start <=end; start++) {
                if (cmp(start, start - 1) < 0) {
                    swap(start, start - 1);
                    //记录最后一次交换的位置
                    sortIndex = start;
                }
            }
            //缩小下一轮扫描范围
            end = sortIndex;

        }
    }

测试:

public static void main(String[] args) {
        //获取一个尾部是有序的
        Integer[] array = Integers.tailAscOrder(1, 100000,3000);
        Integer[] array1 = Integers.copy(array);
        Integer[] array2 = Integers.copy(array);
        assert array != null;
        Times.test("冒泡排序", () -> {
            sort(array);
        });
        Times.test("冒泡排序2", () -> {
            sort2(array1);
        });
        Times.test("冒泡排序3", () -> {
            sort3(array2);
        });
    }

输出:

【冒泡排序】
开始:14:30:09.318
结束:14:30:18.402
耗时:9.084秒
-------------------------------------
【冒泡排序2】
开始:14:30:18.404
结束:14:30:19.368
耗时:0.964秒
-------------------------------------
【冒泡排序3】
开始:14:30:19.369
结束:14:30:19.387
耗时:0.018秒
-------------------------------------

Process finished with exit code 0

参考:小码哥的恋上数据结构第二期