冒泡排序

概念

冒泡排序是一种基础的交换排序。像汽水中的气泡一样向上浮动。

举例

5 8 6 3 9 2 1 7

将8个数字组成的数列按照从小到大顺序排序。

说明

相邻元素两两比较,元素大的放到右边,值相等不交换。过程如下:
冒泡排序_第1张图片

每一轮都会遍历所有元素,进行两两比较,所以说一共需要遍历7轮(元素数量-1),平均时间复杂度是O(n2)。

第一版代码实现

import java.util.Arrays;

public class bubbleSort {
    public static void sort(int[] array) {
        for (int i = 0; i < array.length - 1; i++) {
            for (int j = 0; j < array.length - i - 1; j++) {
                int tmp = 0;
                if (array[j] > array[j + 1]) {
                    tmp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = tmp;
                }
            }
            System.out.println("第"+(i+1)+"轮"+Arrays.toString(array));
        }
    }

    public static void main(String[] args) {
        int[] array = new int[]{5,8,6,3,9,2,1,7};
        sort(array);
        System.out.println("最后排序结果是"+Arrays.toString(array));

    }
}

运行结果:
冒泡排序_第2张图片

第一版缺点

可以发现,第六轮之后已经有序,代码却还是又进行了第七轮。若需要排序的序列为{3,4,2,1,4,5,6,7,8},那么按照以上版本

冒泡排序_第3张图片
可以看出,第3轮已经排好序,程序却又做了4轮的无用功。

第一版优化

这种情况下,如果可以判断出数列已经有序,并作出标记,就可以不必执行剩下几轮排序,提前结束工作。

第二版代码实现

import java.util.Arrays;

public class bubbleSort {
    public static void sort(int[] array) {
        for (int i = 0; i < array.length - 1; i++) {
            //有序标记,每一轮初始值都是true
            boolean isSorted = true;
            for (int j = 0; j < array.length - i - 1; j++) {
                int tmp = 0;
                if (array[j] > array[j + 1]) {
                    tmp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = tmp;
                    //本轮有元素交换,所以不是有序数列,标记为false,还需要下一轮判断
                    isSorted = false;
                }
            }
            //若本轮没有元素交换,跳出循环
            if(isSorted){
                break;
            }
            System.out.println("第"+(i+1)+"轮"+Arrays.toString(array));
        }
    }

    public static void main(String[] args) {
        int[] array = new int[]{3,4,2,1,5,6,7,8};
        sort(array);
        System.out.println("最后排序结果是"+Arrays.toString(array));

    }
}

这一版增加了一个布尔变量isSorted作为标记,若在本轮中有元素交换,则说明数列无序,继续执行下一轮排序;若没有元素交换,则说明数列已经有序,直接跳出大循环。

运行结果:
冒泡排序_第4张图片

第二版缺点

看一下每一轮中两两元素交换的过程
冒泡排序_第5张图片

图中可以发现,其实5,6,7,8这四个数字已经是有序的了,程序却又进行两两比较,这个过程其实duck不必。

第二版优化

可以在每一轮排序后,记录下来最后一次元素交换的位置,该位置就是无序数列的边界,再往后就是有序区了。

第三版代码实现

import java.util.Arrays;

public class bubbleSort {
    public static void sort(int[] array) {
        //记录最后一次交换的位置
        int lastExchangeIndex = 0;
        //无序数列的边界,每次比较只需要比到这里为止
        int sortBoder = array.length - 1;
        for (int i = 0; i < array.length - 1; i++) {
            //有序标记,每一轮初始值都是true
            boolean isSorted = true;
            for (int j = 0; j < sortBoder; j++) {
                int tmp = 0;
                if (array[j] > array[j + 1]) {
                    tmp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = tmp;
                    //本轮有元素交换,所以不是有序数列,标记为false,还需要下一轮判断
                    isSorted = false;
                    //更新为最后一次交换元素的位置
                    lastExchangeIndex = j;
                }
            }
            sortBoder = lastExchangeIndex;
            //若本轮没有元素交换,跳出循环
            if(isSorted){
                break;
            }
            System.out.println("第"+(i+1)+"轮"+Arrays.toString(array));
        }
    }

    public static void main(String[] args) {
        int[] array = new int[]{3,4,2,1,5,6,7,8};
        sort(array);
        System.out.println("最后排序结果是"+Arrays.toString(array));

    }
}

运行结果:
在这里插入图片描述

每一轮交换详情
冒泡排序_第6张图片
这一版的代码中,sortBorder是无序数列的边界。在每一轮排序过程中,处于sortBorder之后的代码就不需要进行比较。这就是
第一轮中5,6,7,8不需要比较;
第二轮中4,5,6,7,8不需要比较;
第三轮中,3,4,5,6,7,8不需要比较

最后

其实这并不是最优的,还有一种排序算法是基于冒泡排序的一种升级排序法:鸡尾酒排序。

如有疑问,欢迎留言评论!

你可能感兴趣的:(《小灰的算法之旅》笔记,#,排序,数据结构,冒泡排序,算法)