冒泡排序

冒泡排序


  1/**
  2 * 冒泡排序的Java实现
  3 * <p>
  4 * 时间复杂度O(n^2),空间复杂度O(1),稳定排序
  5 * </p>
  6 * <b>主要理解思路,实际开发应用基本用不到。</b>
  7 * <p>
  8 * 对于互异数序列,<code>4 5 6 3 2 1</code>,使用冒泡排序对其进行排序应该如何操作?
  9 * <p>
 10 * 冒泡排序的思路:每次冒泡依次比较序列中相邻的元素大小,若前者>后者,则将二者顺序调换。
 11 * 经过一次冒泡,可以保证<b>一个元素在正确的位置上:</b>
 12 * 
 13 * <pre>
 14 *     第一次冒泡的过程:
 15 *       -> 4 5 6 3 2 1
 16 *       -> 4 5 6 3 2 1
 17 *       -> 4 5 3 6 2 1
 18 *       -> 4 5 3 2 6 1
 19 *       -> 4 5 3 2 1 6
 20 *     经过一次冒泡之后,「6」在其正确的位置上了。
 21 * </pre>
 22 * 
 23 * 下面是整个冒泡排序的过程:
 24 * 
 25 * <pre>
 26 *     第一次:4 5 3 2 1 6
 27 *     第二次:4 3 2 1 5 6
 28 *     第三次:3 2 1 4 5 6
 29 *     第四次:2 1 3 4 5 6
 30 *     第五次:1 2 3 4 5 6
 31 *     第六次:1 2 3 4 5 6
 32 * </pre>
 33 * 
 34 * 时间复杂度分析:
 35 * <p>
 36 * 先抛结论:对于N个互异数,通过交换相邻元素进行排序的
 37 * 任何算法(冒泡,插入,选择)时间复杂度都为O(N^2)。
 38 * <p>
 39 * 对于互异数组(不考虑数组内有相同元素的情况)a[N],
 40 * 若<code>a[i] > a[j](i<j)</code>,称(a[i],a[j])为a[N]的一个逆序对;
 41 * 反之,若<code>a[i] > a[j](i>j)</code>,称(a[i],a[j])为a[N]的一个有序对。
 42 * <br>
 43 * 事实上,对互异数排序就是将逆序对通过位置交换变为有序对的过程,
 44 * 因此,有多少逆序对,就需要进行多少次元素交换。
 45 * <br>
 46 * 对于a[N],最好的情形下,它是完全排序的,那么他的逆序对是0,时间复杂度是O(1);
 47 * <br>
 48 * 最坏的情形,它是完全反序的,那么它的逆序对就是N(N-1)/2 (Cn2)个,时间复杂度是O(N^2);
 49 * <br>
 50 * 简化分析,直接取N(N-1)/4为平均情形的逆序对个数,因此平均复杂度为O(N^2)。
 51 *
 52 * @author wangy
 53 * @version 1.0
 54 * @date 2021/7/2 / 16:07
 55 */
 56public class BubbleSort {
 57    /**
 58     * 复杂度分析:
 59     * 无论在什么情况下,大小为N的数组,都要经过N(N-1)/2 次比较过程,
 60     * 因此此算法的时间复杂度为O(N^2)
 61     * <br>
 62     * 不过,由于数组的容量是固定的,并且比较过程中只使用了2个变量,
 63     * 故此方法的空间复杂度为O(1)
 64     * <br>
 65     * 实际上,这个方法还可以优化,如果已经排序好了,那么就不需要再去比较了。
 66     * 这样可以大大降低复杂度。
 67     *
 68     * @param a 待排序数组
 69     */
 70    static void bubble(int[] a) {
 71        int size = a.length;
 72        for (int i = 0; i < size; i++) {
 73            // 内层循环边界为(size-i-1)
 74            // 因第i次冒泡,应有i个元素已经处于正确的位置,无需再比较
 75            for (int j = 0; j < size - i - 1; j++) {
 76                // swap if f > e
 77                int f = a[j];
 78                int e = a[j + 1];
 79                if (f > e) {
 80                    a[j] = e;
 81                    a[j + 1] = f;
 82                }
 83                System.out.println("\t====>\t" + Arrays.toString(a));
 84            }
 85            System.out.println(Arrays.toString(a));
 86        }
 87    }
 88
 89    // 内层循环如果没有数据交换 --> 已经完全排序,可以跳出冒泡过程。
 90    static void bubble2(int[] a) {
 91        int size = a.length;
 92        for (int i = 0; i < size; i++) {
 93            boolean swaped = false;
 94            // 内层循环边界为(size-i-1)
 95            // 因第i次冒泡,应有i个元素已经处于正确的位置,无需再比较
 96            for (int j = 0; j < size - i - 1; j++) {
 97                // swap if before > after
 98                if (a[j] > a[j + 1]) {
 99                    int tmp = a[j];
100                    a[j] = a[j + 1];
101                    a[j + 1] = tmp;
102                    swaped = true;
103                }
104                System.out.println("\t====>\t" + Arrays.toString(a));
105                if (!swaped)
106                    break;
107            }
108            System.out.println(Arrays.toString(a));
109        }
110    }
111
112    public static void main(String[] args) {
113        // int[] a = new int[]{4, 5, 6, 3, 2, 1};
114        int[] a = new int[] { 1, 2, 3, 4, 5, 6 };
115        BubbleSort.bubble2(a);
116    }
117}