BubbleSort

1.动图演示

2.代码实现

2.1 测试工具类


import java.lang.reflect.Method;

/**
 * 测试排序的工具类
 * 后续测试其他排序时也会用到
 */
public class SortTestHelper {

    // private 修饰构造方法。不允许产生任何该类实例
    private SortTestHelper() {
    }

    /**
     * 生成有n个元素的随机数组,每个元素的随机范围为[rangeL, rangeR]
     */
    public static Integer[] generateRandomArray(int n, int rangeL, int rangeR) {

        assert rangeL <= rangeR;

        Integer[] arr = new Integer[n];

        for (int i = 0; i < n; i++)
            arr[i] = new Integer((int) (Math.random() * (rangeR - rangeL + 1) + rangeL));
        return arr;
    }

    /**
     *  打印arr数组的所有内容
     */
    public static void printArray(Object arr[]) {

        for (int i = 0; i < arr.length; i++) {

            System.out.print(arr[i]);
            System.out.print(' ');
            if (i > 0 && i % 50 == 0)
                System.out.println();

        }
        System.out.println();
        return;
    }


    /**
     * 测试sortClassName所对应的排序算法排序arr数组所得到结果的正确性和算法运行时间
     * 这里通过反射调用某个排序的sort()方法
     * 具体调用哪一个类的sort 通过传入的类名来决定。
     * 不了解Java反射机制的话可以跳过,这对于测试排序算法来说不重要。
     */
    public static void testSort(String sortClassName, Comparable[] arr) {
        // 通过Java的反射机制,通过排序的类名,运行排序函数

        try {
            // 通过sortClassName获得排序函数的Class对象
            Class sortClass = Class.forName(sortClassName);
            //通过类对象获取排序方法
            Method sortMethod = sortClass.getMethod("sort", Comparable[].class);//new Class[]{   }
            //排序参数,可比较对象的数组
            Object[] params = new Object[]{arr};

            long startTime = System.currentTimeMillis();
            //调用排序方法
            sortMethod.invoke(null, params);
            long endTime = System.currentTimeMillis();
            assert isSorted(arr);
            System.out.println(sortClass.getSimpleName() + " : " + (endTime - startTime) + "ms");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 判断arr数组是否有序
     */
    private static boolean isSorted(Comparable[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            if (arr[i].compareTo(arr[i + 1]) > 0) {
                throw new RuntimeException("排序失败");
            }
        }

        return true;
    }

    /**
     * 先生产一个有序数组,随机挑选几个交换位置,返回一个近乎有序的数组。
     */
    public static Integer[] generateNearlyOrderedArray(int n, int swapTimes) {
        Integer[] arr = new Integer[n];
        for (int i = 0; i < n; i++) {
            arr[i] = i;
        }
        for (int i = 0; i < swapTimes; i++) {
            int x = (int) (Math.random() * n);
            int y = (int) (Math.random() * n);
            Integer t = arr[x];
            arr[x] = arr[y];
            arr[y] = t;
        }
        return arr;

    }

    /**
     * 数组中index为 i 和 j 的元素 交换位置
     */
    public static void swap(Object[] arr, int i, int j) {
        Object t = arr[i];
        arr[i] = arr[j];
        arr[j] = t;
    }

}

2.2 冒泡排序代码


/**
 * 冒泡排序
 */
public class BubbleSort {

    // 算法类不允许产生任何实例
    private BubbleSort(){}

    public static void sort(Comparable[] arr){

        int n = arr.length;
        int newn;

        do{
            newn = 0;
            for( int i = 1 ; i < n ; i ++ )
                if( arr[i-1].compareTo(arr[i]) > 0 ){
                    swap( arr , i-1 , i );
                    // 可以记录最后一次的交换位置,在此之后的元素在下一轮扫描中均不考虑
                    newn = i;
                }
            n = newn;
        }while(newn > 0);
    }

    private static void swap(Object[] arr, int i, int j) {
        Object t = arr[i];
        arr[i] = arr[j];
        arr[j] = t;
    }
  public static void main(String[] args) {
        int N = 10000;
        Integer[] arr = SortTestHelper.generateRandomArray(N, 0, 1000);
        SortTestHelper.testSort("sort.BubbleSort", arr);
        int N2 = 20000;
        Integer[] arr2 = SortTestHelper.generateRandomArray(N2, 0, 1000);
        SortTestHelper.testSort("sort.BubbleSort", arr2);
        int N3 = 30000;
        Integer[] arr3 = SortTestHelper.generateRandomArray(N3, 0, 1000);
        SortTestHelper.testSort("sort.BubbleSort", arr3);
    }
}

3.测试结果

这里是初步的测试,后续文章会结合多个类型的排序,对于不同类型的数组排序,比较各个排序算法的性质。

4.算法分析

4.1描述

比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

4.2分析


in-place 不占用额外的空间。显然,若数组存在相同元素,不会交换位置,因此冒泡排序是稳定的。