算法01——冒泡排序+对数器

算法思想

冒泡排序是一种交换排序

交换排序:两两比较待排序的关键字,把不满足次序要求的两个数交换,直到全部关键字都满足次序要求为止。

冒泡排序的算法思想:假设要对N个数进行排序,第一趟,先比较0位置和1位置的两个数,如果不满足要求就交换两个数,满足要求则不动,再比较1位置和2位置的数,以此类推,一直比较到最后两个数,此时,最后一个数就是最大(小)的。第二趟,从1位置的数开始两两比较。每一趟排除已经确定的数。将越来越少的数两两比较直到所有的数都完成排序。趟数为N-1。

例子:

 例如:10 2 8 7
 第一轮
 (1)10>2,二者交换位置:2 10 8 7
 (2)10>8,二者交换位置:2 8 10 7
 (3)10>7,二者交换位置:2 8 7 10
 这一轮结束,下一轮不再比较最后一个元素

 第二轮
 (1)2<8,不交换位置:2 8 7 10
 (2)8>7.交换位置:2 7 8 10
 结束这一轮,下一轮不再比较最后二个元素

 第三轮
 (1)2<7,不交换:2 7 8 10
 
 排序结束。

Java代码实现

    public static void bubblesort(int arr[]){
        //为空,或长度小于2,不排序直接返回
        if(arr==null || arr.length<2){
            System.out.println("长度过短,不能进行排序");
            return;
        }
//        一共比较数组长度-1轮
        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);
                }
            }
        }
    }

  private static void swap(int[] arr, int i, int j) {
        int temp=0;
        temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

public static void bubblesort2(int arr[]){
        //为空,或长度小于2,不排序直接返回
        if(arr==null || arr.length<2){
            System.out.println("长度过短,不能进行排序");
            return;
        }
//外层循环,遍历次数为数组长度-1
        for (int i = arr.length - 1; i > 0; i--) {
            for (int j = 0; j < i; j++) {
                if (arr[j] > arr[j + 1]) {
                    swap(arr, j, j + 1);
                }
            }
        }
    }

用对数器对算法进行正确性测试

对数器的概念:

0:有一个你想要测的方法a

1:实现一个绝对正确但是复杂度不好的方法b

2:实现一个随机样本产生器

3:实现比对的方法

4:把方法a和方法b比对很多次来验证方法a是否正确

5:如果有一个样本使得比对出错,打印样本分析是哪个方法出错

6:当样本数量很多时比对测试依然正确,可以确定方法a已经正确


下面用代码一步步实现对数器

0:有一个你想要测的方法a

上面所实现的冒泡排序

1:实现一个绝对正确但是复杂度不好的方法b

这里使用系统的排序算法

//    绝对正确的方法
public static void rightMethod(int[] arr) {
    Arrays.sort(arr);
}

2:实现一个随机样本产生器

 //随机数组生成器
    public static int[] generateRandomArray(int size, int value) {
        /*
         ************java中的数字随机生成**********

         Math.random() -> double [0,1)
        (int)((size+1)*Math.random()) -> int [0,size]
        例如size=5,size+1=6
        [0,1) * 6 ->  double [0,6) -> int [0,5]

         */


//        生成随机长度(0-size)
        int[] arr = new int[(int) (Math.random() * (size + 1))];
//        生成随机数字(-value 到 value)
        for (int i = 0; i < arr.length; i++) {
            arr[i] = (int) ((value + 1) * Math.random()) - (int)(value * Math.random());
        }
        return arr;
    }

3:实现比对的方法

//判断两个数组是否相等
public static boolean isEqual(int[] a1, int[] a2) {
    if ((a1 == null && a2 != null) || (a1 != null && a2 == null)) {
        return false;
    }
    if (a1 == null && a2 == null) {
        return true;
    }
    if (a1.length != a2.length) {
        return false;
    }
    for (int i = 0; i < a1.length; i++) {
        if (a1[i] != a2[i]) {
            return false;
        }
    }
    return true;
}

4:把方法a和方法b比对很多次来验证方法a是否正确

5:如果有一个样本使得比对出错,打印样本分析是哪个方法出错

public static void main(String[] args) {

    int testTime=10000;
    int size=20;
    int value=50;

    boolean isSucceed = true;
    for (int i = 0; i < testTime; i++) {
        int[] a1 = generateRandomArray(size, value);
        int[] a2 = copyArr(a1);
        int[] a3 = copyArr(a1);
        bubblesort2(a1);
        rightMethod(a2);
        if (!isEqual(a1, a2)) {
            isSucceed = false;
            //打印出出现bug的样本
            System.out.println("发生错误的样本:"+Arrays.toString(a3));
            break;
        }
    }
    System.out.println(isSucceed ? "↓ Good Job!" : "fail");
    int[] arr = generateRandomArray(size, value);
    System.out.println(Arrays.toString(arr));
    bubblesort2(arr);
    System.out.println(Arrays.toString(arr));
}

6:当样本数量很多时比对测试依然正确,可以确定方法a已经正确

附:copyArr方法

//拷贝数组
public static int[] copyArr(int[] arr) {
    if (arr == null) {
        return null;
    }
    int[] res = new int[arr.length];
    for (int i = 0; i < arr.length; i++) {
        res[i] = arr[i];
    }
    return res;
}

对数器测试结果


时间复杂度

冒泡排序的时间复杂度按照最坏情况来说是:O(N²)


算法稳定性

冒泡排序是两两比较,不满足要求的才会交换。两个相同元素的前后顺序不会发生变化,所以冒泡排序是一种稳定排序算法。

posted @ 2019-07-18 14:58  Jotal  阅读(275)  评论(0编辑  收藏  举报