冒泡排序算法

Posted 可持续化发展

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了冒泡排序算法相关的知识,希望对你有一定的参考价值。

冒泡排序有三种写法:

  1. 一边比较一边向后两两交换,将最大值 / 最小值冒泡到最后一位;
  2. 经过优化的写法:使用一个变量记录当前轮次的比较是否发生过交换,如果没有发生交换表示已经有序,不再继续排序;
  3. 进一步优化的写法:除了使用变量记录当前轮次是否发生交换外,再使用一个变量记录上次发生交换的位置,下一轮排序时到达上次交换的位置就停止比较。
package practice;
import java.util.*;


public class Main {
	
    public static void main(String[] args) {
    	int[] arr = new int[] {88,32,1,9,4,23,8,9};
//    	bubbleSort1(arr);
//    	bubbleSort2(arr);
    	bubbleSort3(arr);
    	for(int i : arr) {
    		System.out.print(i+",");
    	}
    	System.out.println();
    	int a = 9, b = 3;
    	System.out.println("a="+a+",b="+b);
    	a = a ^ b;
    	b = b ^ a;
    	a = a ^ b;
    	System.out.println("a="+a+",b="+b);
    	a = 3; b = 3;
    	System.out.println("a="+a+",b="+b);
    	a = a ^ b;
    	b = b ^ a;
    	a = a ^ b;
    	System.out.println("a="+a+",b="+b);
    	
    }
    
    //冒泡排序的第一种写法
    public static void bubbleSort1(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    // 如果左边的数大于右边的数,则交换,保证右边的数字最大
                    swap(arr, j, j + 1);
                }
            }
        }
    }
    
    //冒泡排序的第二种写法
    public static void bubbleSort2(int[] arr) {
        // 初始时 swapped 为 true,否则排序过程无法启动
        boolean swapped = true;
        for (int i = 0; i < arr.length - 1; i++) {
            // 如果没有发生过交换,说明剩余部分已经有序,排序完成
            if (!swapped) break;
            // 设置 swapped 为 false,如果发生交换,则将其置为 true
            swapped = false;
            for (int j = 0; j < arr.length - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    // 如果左边的数大于右边的数,则交换,保证右边的数字最大
                    swap(arr, j, j + 1);
                    // 表示发生了交换
                    swapped = true;
                }
            }
        }
    }
    
    //冒泡排序的第三种写法
    public static void bubbleSort3(int[] arr) {
        boolean swapped = true;
        // 最后一个没有经过排序的元素的下标
        int indexOfLastUnsortedElement = arr.length - 1;
        // 上次发生交换的位置
        int swappedIndex = -1;
        while (swapped) {
            swapped = false;
            for (int i = 0; i < indexOfLastUnsortedElement; i++) {
                if (arr[i] > arr[i + 1]) {
                    // 如果左边的数大于右边的数,则交换,保证右边的数字最大
                    swap(arr, i, i + 1);
                    // 表示发生了交换
                    swapped = true;
                    // 更新交换的位置,交换二者中的前者
                    swappedIndex = i;
                }
            }
            // 最后一个没有经过排序的元素的下标就是最后一次发生交换的位置,用来控制for循环
            indexOfLastUnsortedElement = swappedIndex;
        }
    }
    // 交换元素
    private static void swap(int[] arr, int i, int j) {
        arr[i] = arr[i] ^ arr[j];
        arr[j] = arr[j] ^ arr[i];
        arr[i] = arr[i] ^ arr[j];
    }
}


交换的技巧
一般来说,交换数组中两个数字的函数如下:
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
但在大厂面试中,有一道非常经典的数字交换题目:如何在不引入第三个中间变量的情况下,完成两个数字的交换。

这里可以用到一个数学上的技巧:

arr[j + 1] = arr[j + 1] + arr[j];
arr[j] = arr[j + 1] - arr[j];
arr[j + 1] = arr[j + 1] - arr[j];
除了这种先加后减的写法,还有一种先减后加的写法:
Java

arr[j + 1] = arr[j] - arr[j + 1];
arr[j] = arr[j] - arr[j + 1];
arr[j + 1] = arr[j + 1] + arr[j];
但这两种方式都可能导致数字越界。

更好的方案是通过位运算完成数字交换:
arr[i] = arr[i] ^ arr[j];
arr[j] = arr[j] ^ arr[i];
arr[i] = arr[i] ^ arr[j];

以上是关于冒泡排序算法的主要内容,如果未能解决你的问题,请参考以下文章

排序算法之冒泡选择插入排序(Java)

排序算法_冒泡排序(算法设计与C代码实现)

冒泡排序算法原理和代码实现,就是这么简单。。。

三大基础排序算法(冒泡排序,选择排序,插入排序)

交换排序(冒泡排序快速排序的算法思想及代码实现)

算法漫游指北(第七篇):冒泡排序冒泡排序算法描述动图演示代码实现过程分析时间复杂度和选择排序算法描述动图演示代码实现过程分析时间复杂度