排序算法(2)-冒泡排序及优化

1.冒泡排序

之前写过一个排序算法(1),其中总结了冒泡排序 .
冒泡排序的思想,是把相邻的元素两两比较,根据大小来交换元素的位置,每经过一轮的扫描,就会确定出一个最大的元素,即是一个元素有序.

原始的冒泡排序是稳定排序(如果一个数组中存在几个相同的元素,排序前后的相同元素的前后顺序不会发生变更,则认为排序是稳定的)。由于该排序算法的每一轮要遍历所有元素,轮转的次数和元素数量相当,所以时间复杂度是O(N^2) 。

代码如下:

 /**
     * @description 冒泡排序
     * @author zhangdi
     * @param arr
     * @description : 两两比较,大的往后放; 每一次比较完成之后,下一次就少比较一个元素
     *              第一次比较有0个元素不比较;第二次有一个元素不需要比较;第三次有两个元素不需要比较;
     *              共需要比较arr.length-1次
     */
    public static void BubbleSort(int[] arr) {

        int temp;// 临时变量
        if (arr == null || arr.length == 0)
            return;
        for (int i = 0; i < arr.length - 1; i++) { // 表示趟数,一共arr.length-1次。
            for (int j = arr.length - 1; j > i; j--) {

                if (arr[j] < arr[j - 1]) {
                    temp = arr[j];
                    arr[j] = arr[j - 1];
                    arr[j - 1] = temp;
                }
            }
        }
    }

    /**
     * @description 冒泡排序-2
     * @param arr
     * @author zhangdi
     */
    public static void BubbleSort2(int[] arr) {

        int temp;// 临时变量
        if (arr == null || arr.length == 0)
            return;
        for (int i = 0; i < arr.length - 1; i++) { // 表示趟数,一共arr.length-1次。
            for (int j = 0; j < arr.length - 1 - i; j++) {

                if (arr[j] > arr[j + 1]) {
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }

2冒泡排序改进

现在我们思考一下,会发现这个算法还有优化的空间,比如说但是一个数组前一半部分已经是有序的,当某轮中没有发生元素交换,就可以确定,整个数组已经是有序的,此时就不需要进行接下来的扫描交换了.


    /**
     * @description 冒泡排序-1-优化
     * @author zhangdi
     * @param arr
     *            * 针对问题:数据的顺序排好之后,冒泡算法仍然会继续进行下一轮的比较,直到arr.length-1次,后面的比较没有意义的。
     *            方案: 设置标志位flag,如果发生了交换flag设置为true;如果没有交换就设置为false。
     *            这样当一轮比较结束后如果flag仍为false,即:这一轮没有发生交换,说明数据的顺序已经排好,没有必要继续进行下去。
     * 
     */
    public static void BubbleSort1_better(int[] arr) {

        int temp;// 临时变量
        boolean flag;
        if (arr == null || arr.length == 0)
            return;
        for (int i = 0; i < arr.length - 1; i++) { // 表示趟数,一共arr.length-1次。
            flag = false;
            for (int j = arr.length - 1; j > i; j--) {
                if (arr[j] < arr[j - 1]) {
                    temp = arr[j];
                    arr[j] = arr[j - 1];
                    arr[j - 1] = temp;
                }
            }
            if (!flag)
                break;
        }
    }

冒泡排序三改进

上面的算法还有优化的空间吗?答案是有,假如存在一个数组,前缀几个元素是无序的,而后面大部分皆是有序的,上面的版本并不能解决这种情况下出现的中间部分的反复的扫描,这些扫描交换的元素集中在数组前部.
多出来的时间消耗是后缀中已经有序的元素的反复的扫描交换,其实是不必要的;–>如何确定最后扫描交换的元素的标志在哪?而不是亦步亦趋的逐步收缩.
由此得出版本三

    /**
     * @description 冒泡排序-3
     * @param arr
     * @author zhangdi
     */
    private static void BubbleSort1_better(int[] array) {
        int tmp = 0;
        // 记录最后一次交换的位置
        int lastExchangeIndex = 0;
        // 无序数列的边界,每次比较只需要比到这里为止
        int sortBorder = array.length - 1;
        for (int i = 0; i < array.length; i++) {
            // 有序标记,每一轮的初始是true
            boolean isSorted = true;
            for (int j = 0; j < sortBorder; j++) {
                if (array[j] > array[j + 1]) {
                    tmp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = tmp;
                    // 有元素交换,所以不是有序,标记变为false
                    isSorted = false;
                    // 把无序数列的边界更新为最后一次交换元素的位置
                    lastExchangeIndex = j;
                }
            }
            sortBorder = lastExchangeIndex;
            if (isSorted) {
                break;
            }
        }
    }

猜你喜欢

转载自blog.csdn.net/ShelleyLittlehero/article/details/81105673
今日推荐