【八大排序】day1.冒泡排序

一、交换排序

交换排序:通过比较序列中任意位置的两个元素,根据比较结果来进行交换,以此达到排序的目的

二、冒泡排序

/**
 * 冒泡排序:
 * 冒泡排序是一种简单的交换排序算法,以升序为例
 * 1.从第一个数开始,比较相邻的两个元素,如果第一个比第二个大,那么两个元素交换位置
 * 2.轮到下一轮继续相邻两个元素之间比较并且交换,直到没有可以交换的元素
 * 3.除了每一轮排序所得到的最后一个元素,对剩余元素继续比较,直到没有可以比较的元素
 */
public static void bubble1(Integer[] arr) {
        if (arr == null) {
            throw new NullPointerException();
        }
        int n = arr.length;
        if (n == 1) {
            return;
        }
        int temp;
        for (int i = 0; i < n - 1; i++) {
            for (int j = 0; j < n - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }

三、优化(1)

/**
 * 优化1:
 * 假如待排序数组是 2、1、3、4、5 这样的情况,按照上面的代码实现,
 * 第一轮循环结束后就得到了最终结果。但循环不会停止,而是继续执行,直到结束为止。
 * 为了解决这个问题,我们可以设置一个标志位,用来判断当前循环有没有进行交换,
 * 如果没有交换那就说明已经完成了排序,直接返回就好。
 */
public static int bubble2(Integer[] arr) {
        int count = 0;
        if (arr == null) {
            throw new NullPointerException();
        }
        int n = arr.length;
        if (n == 1) {
            return count;
        }
        int temp;
        for (int i = 0; i < n - 1; i++) {
            int flag = 0;
            for (int j = 0; j < n - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                    flag = 1; //交换时进行标记
                    count++; //记录循环次数
                }
            }
            if (flag == 0) { //没有进行交换,说明已经完成排序
                return count;
            }
        }
        return count;
    }

四、优化(2)

/**
 * 优化2:
 * 比如3、4、2、1、6、7、8 这个数组,第一次循环后,变为 3、2、1、4、6、7、8 的顺序,
 * 我们发现,1 之后的 4 、6、7、8 已经有序了,第二次循环就没必要对后面这段再遍历比较。
 * 那么我们需要找到这么一个分界点,其实也不难找,可以想象,由于i之前的元素是无序的,
 * 所以一定有交换发生,而i之后的元素是有序的,不会有交换发生,最后发生交换的地点,
 * 就是我们要找的分界点。
 */
public static int bubble3(Integer[] arr) {
        int count = 0;
        if (arr == null) {
            throw new NullPointerException();
        }
        int n = arr.length - 1;
        if (n == 1) {
            return count;
        }
        int temp;
        for (int i = 0; i < n; i++) {
            int lastChange = 0; //最后一次改变的位置
            for (int j = 0; j < n; j++) {
                if (arr[j] > arr[j + 1]) {
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                    lastChange = j; //实时更新最后一次交换的位置
                    count++;
                }
            }
            if (lastChange == 0) { //没有进行交换,说明已经完成排序
                return count;
            }
            n = lastChange; //把最后一次交换的位置作为下一次循环的终点
        }
        return count;
    }

五、全部代码

public class _1_BubbleSort {
    public static void main(String[] args) {
        //基础冒泡排序
        Integer[] arr1 = {3, 5, 1, 7, 2, 3, 4, 8};
        bubble1(arr1);
        System.out.println(Arrays.toString(arr1));

        //优化1:中途根据标志位判断排序是否完成
        Integer[] arr2 = {2, 1, 3, 4, 5};
        System.out.println("循环的次数 = " + bubble2(arr2));
        System.out.println(Arrays.toString(arr2));

        //优化2:根据一次循环中最后一次交换的位置来减少无意义的遍历
        Integer[] arr3 = {3, 5, 1, 7, 2, 3, 4, 8};
        System.out.println("循环的次数 = " + bubble3(arr3));
        System.out.println(Arrays.toString(arr3));

    }

    /**
     * 冒泡排序:
     * 冒泡排序是一种简单的交换排序算法,以升序为例
     * 1.从第一个数开始,比较相邻的两个元素,如果第一个比第二个大,那么两个元素交换位置
     * 2.轮到下一轮继续相邻两个元素之间比较并且交换,直到没有可以交换的元素
     * 3.除了每一轮排序所得到的最后一个元素,对剩余元素继续比较,直到没有可以比较的元素
     */
    public static void bubble1(Integer[] arr) {
        if (arr == null) {
            throw new NullPointerException();
        }
        int n = arr.length;
        if (n == 1) {
            return;
        }
        int temp;
        for (int i = 0; i < n - 1; i++) {
            for (int j = 0; j < n - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }

    /**
     * 优化1:
     * 假如待排序数组是 2、1、3、4、5 这样的情况,按照上面的代码实现,
     * 第一轮循环结束后就得到了最终结果。但循环不会停止,而是继续执行,直到结束为止。
     * 为了解决这个问题,我们可以设置一个标志位,用来判断当前循环有没有进行交换,
     * 如果没有交换那就说明已经完成了排序,直接返回就好。
     */
    public static int bubble2(Integer[] arr) {
        int count = 0;
        if (arr == null) {
            throw new NullPointerException();
        }
        int n = arr.length;
        if (n == 1) {
            return count;
        }
        int temp;
        for (int i = 0; i < n - 1; i++) {
            int flag = 0;
            for (int j = 0; j < n - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                    flag = 1; //交换时进行标记
                    count++; //记录循环次数
                }
            }
            if (flag == 0) { //没有进行交换,说明已经完成排序
                return count;
            }
        }
        return count;
    }

    /**
     * 优化2:
     * 比如3、4、2、1、6、7、8 这个数组,第一次循环后,变为 3、2、1、4、6、7、8 的顺序,
     * 我们发现,1 之后的 4 、6、7、8 已经有序了,第二次循环就没必要对后面这段再遍历比较。
     * 那么我们需要找到这么一个分界点,其实也不难找,可以想象,由于i之前的元素是无序的,
     * 所以一定有交换发生,而i之后的元素是有序的,不会有交换发生,最后发生交换的地点,
     * 就是我们要找的分界点。
     */
    public static int bubble3(Integer[] arr) {
        int count = 0;
        if (arr == null) {
            throw new NullPointerException();
        }
        int n = arr.length - 1;
        if (n == 1) {
            return count;
        }
        int temp;
        for (int i = 0; i < n; i++) {
            int lastChange = 0; //最后一次改变的位置
            for (int j = 0; j < n; j++) {
                if (arr[j] > arr[j + 1]) {
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                    lastChange = j; //实时更新最后一次交换的位置
                    count++;
                }
            }
            if (lastChange == 0) { //没有进行交换,说明已经完成排序
                return count;
            }
            n = lastChange; //把最后一次交换的位置作为下一次循环的终点
        }
        return count;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值