1

作者前言

大家好,我是阿濠,今篇内容跟大家分享的是排序算法之冒泡排序,很高兴分享到segmentfault与大家一起学习交流,初次见面请大家多多关照,一起学习进步.

一、冒泡排序的介绍

基本介绍

冒泡排序(Bubble Sorting) 的基本思想是:通过对待排序序列从前向后(从下标较小的元素开始) , 依次比较相邻元素的值,若发现逆序则交换使值较大的元素逐渐从前移向后部,就象水底下的气泡一样逐渐向上冒。

优化思路

(因为排序的过程中各元素不断接近自己的位置,如果一趟比较下来没有进行过交换,就说明序列有序,因此可以在排序过程中设置个标志flag判断元素是否进行过交换。从而减少不必要的比较。可以在冒泡排序写好后,再进行)

二、应用示例认识冒泡排序

将五个无序的数: 3,9,-1, 10, 20 使用冒泡排序法将其排成一个从小到大的有序数列。

步骤思路:
1.需要进行数组大小-1的循环
2.比较相邻的元素,如果比较大则交换两个
3.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对

代码推演每次排序的过程

int arr[] = {3, 9, -1, 10, -2};
//为了容量理解,我们把冒泡排序的演变过程,给大家展示
//第一趟排序,就是将最大的数排在最后
int temp = 0; //临时变量
for(int j =0;j < arr.length -1;j ++){
    //如果前面的数比后面的数大,则交换
    if (arr[j] > arr[j + 1]) {
        temp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
    }
}
System.out.println("第一趟排序后的数组");
System.out.println(Arrays.toString(arr));

运行结果如下:
第一趟排序后的数组:[3,-1,9,-2,10]
//第二趟排序,就是将第二大的数排在倒数第二位
for(int j =0;j < arr.length -1 -1 ;j ++){
    //如果前面的数比后面的数大,则交换
    if (arr[j] > arr[j + 1]) {
        temp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
    }
}

System.out.println("第二趟排序后的数组");
System.out.println(Arrays.toString(arr));

运行结果如下:
第二趟排序后的数组:[-1,3,-2,9,10]
//第三趟排序,就是将第三大的数排在倒数第三位
for(int j =0;j < arr.length -1 -2 ;j ++){
    //如果前面的数比后面的数大,则交换
    if (arr[j] > arr[j + 1]) {
        temp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
    }
}

System.out.println("第三趟排序后的数组");
System.out.println(Arrays.toString(arr));

运行结果如下:
第三趟排序后的数组:[-1,-2,3,9,10]

.......

我们发现for循环的相关部分相似,改变的是每次循环的次数,即进行如下代码抽整:

//进行排序,将最大的数排在最后,时间复杂度是 O(n^2)
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]) {
            temp = arr[j];
            arr[j] = arr[j + 1];
            arr[j + 1] = temp;
        }
    }
    System. out. println("第"+(i+1)+"趟排序后的数组");
    System. out.println(Arrays.toString(arr));
}

运行结果如下:
第1趟排序后的数组:[3,-1,9,-2,10]
第2趟排序后的数组:[-1,3,-2,9,10]
第3趟排序后的数组:[-1,-2,3,9,10]
第4趟排序后的数组:[-2,-1,3,9,10]

使用标志性变量避免交换

加入标志性变量flag,用于标志某一趟排序过程中是否有数据交换,如果进行某一趟排序时并没有进行数据交换,则说明数据已经按要求排列好,可立即结束排序避免不必要的比较过程

boolean flag=false;
//排序,就是将最大的数排在最后没时间0(n^2)
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]) {
            flag=true;
            temp = arr[j];
            arr[j] = arr[j + 1];
            arr[j + 1] = temp;
        }
    }
    //证明在一趟排序中,没有进行交换
    if(!flag){
        break;
    }else{
        //重置flag,进行下次判断
        flag=false;
    }
    System. out. println("第"+(i+1)+"趟排序后的数组");
    System. out.println(Arrays.toString(arr));
}

三、复杂度分析

空间复杂度:O(1)

假设数组的元素个数是n,整个排序的过程中,直接在给定的数组里进行元素的两两交换

时间复杂度:O(n^2)

情景一:给定的数组按照顺序已经排好
只需要进行n- 1次的比较,两两交换次数为0时间复杂度是O(n),这是最好的情况

情景二:给定的数组按照逆序排列
需要进行n(n- 1)/ 2次比较时间复杂度是O(n^2),这是最坏的情况

情景三:给定的数组杂乱无章
在这种情况下,平均时间复杂度是O(n^2)


28640
116 声望25 粉丝

心有多大,舞台就有多大