冒泡排序

本文详细介绍了冒泡排序的工作原理,通过举例说明了冒泡排序如何进行升序排列,并分析了冒泡排序在不同情况下的时间复杂度,无论是最优、最差还是平均情况,冒泡排序的时间复杂度均为O(n^2)。同时,提到了通过添加标志位优化冒泡排序的可能性。
摘要由CSDN通过智能技术生成
冒泡排序(Bubble Sort)是一种简单的排序算法。
   
它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。
走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。
这个算法的名字由来是因为最小(或最大)的元素会经由交换慢慢“浮”到数列的顶端。

以"由小到大"排序为例:

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


相当于多次循环,每次找出序列中最大的一个数放到最后端;

如果10个数,第一次从10个数中找到最大的数,放到最后面,

第二次从前9个数中找到最大的数,放到第一次找到的最大数的前面;

java代码:
/**
 * 冒泡排序
 * 由小到大排序
 * @param array
 */
public static void bubbleSort(int[] array) {
    int temp;
    //第一层循环:表明要比较的趟数,比如array.length个数,要做array.length-1趟排序
    for(int i=0; i<array.length-1; i++) {
        //第二层循环:表明一趟排序要比较的次数
        //由于每一趟排序会得出一个最大的数,放到最后,下一趟排序则不比较这些最大的数,所以比较的次数j会越来越小
        for(int j=0 ; j<array.length-1-i; j++){
            //如果前面一个数大于后面一个数则交换
            if(array[j] > array[j+1]) {
                temp = array[j];
                array[j] = array[j+1];
                array[j+1] = temp;
            }
        }
    }
}


时间复杂度

冒泡排序是一种用时间换空间的排序方法,最坏情况是把顺序的排列变成逆序,或者把逆序的数列变成顺序。
在这种情况下,每一次比较都需要进行交换运算。

举个例子来说,一个数列 5 4 3 2 1 进行冒泡升序排列,
第一次大循环从第一个数(5)开始到UI后一个数(1)结束,比较过程:
先比较5和4,4比5小,交换位置变成4 5 3 2 1;
比较5和3,3比5小,交换位置变成4 3 5 2 1……
最后比较5和1,1比5小,交换位置变成4 3 2 1 5。
这时候共进行了4次比较交换运算,最后1个数变成了数列最大数。

第二次大循环从第一个数(4)开始到倒数第二个数(1)结束。进行3次比较交换运算。
……

所以总的比较次数为 4 + 3 + 2 + 1 = 10次

对于n位的数列则有比较次数为 (n-1) + (n-2) + ... + 1 = n * (n - 1) / 2,这就得到了最大的比较次数
而O(N^2)表示的是复杂度的数量级。

举个例子来说,如果n = 10000,那么 n(n-1)/2 = (n^2 - n) / 2 = (100000000 - 10000) / 2,
相对10^8来说,10000小的可以忽略不计了,所以总计算次数约为0.5 * N^2。
用O(N^2)就表示了其数量级(忽略前面系数0.5)。

最优的情况也就是开始就已经排好序了,那么就可以不用交换元素了,则时间花销为:[ n(n-1) ] /  2;
(还是要遍历完的都)所以最优的情况时间复杂度为:O( n^2 );

最差的情况也就是开始的时候元素是逆序的,那么每一次排序都要交换两个元素,则时间花销为:[ n(n-1) ] / 2;
(其中比上面最优的情况所花的时间就是在于交换元素的三个步骤(忽略));所以最差的情况下时间复杂度为:O( n^2 );

综上所述:
最优的时间复杂度为:O( n^2 ) ;有的说 O(n),下面会分析这种情况;
最差的时间复杂度为:O( n^2 );
平均的时间复杂度为:O( n^2 );

最优时间复杂度 n

有很多人说冒泡排序的最优的时间复杂度为:O(n);其实这是在代码中使用一个标志位来判断是否已经排序好的,修改下代码:

void bubbleSort(int array[], int length)  
    {  
        int i, j, tmp;  
        boolean flag = false;  
          
        if (1 >= length) return;  
      
        for (i = length-1; i > 0; i--){   
            for (j = 0; j < i; j++){  
                if (array[j] > array[j+1]){  
                    tmp        = array[j];  
                    array[j]   = array[j+1];  
                    array[j+1] = tmp;  
                    flag = true;  
                }     
            }     
            if (!flag) break;  
        }     
    }
根据上面的代码可以看出,如果元素已经排序好,那么循环一次就直接退出。
或者说元素开始就已经大概有序了,那么这种方法就可以很好减少排序的次数;
其实我感觉这种方法也有弊端,比如 要额外的判断下,以及赋值操作;

空间复杂度
空间复杂度就是在交换元素时那个临时变量所占的内存空间;
最优的空间复杂度就是开始元素顺序已经排好了,则空间复杂度为:0;
最差的空间复杂度就是开始元素逆序排序了,则空间复杂度为:O(n);
平均的空间复杂度为:O(1);

空间复杂度为 0
有人会说这个空间复杂度能降到0,因为空间复杂度主要是看使用的辅助内存,
如果没有辅助内存变量,那么可以说空间复杂度为0;
所以该算法中空间复杂度一般是看交换元素时所使用的辅助空间;
1、 a  = a + b; b = a - b; a = a - b;
2、 a = a * b;   b =  a / b; a = a / b;
3、 a = a ^ b;  b =  a ^ b;a = a ^ b;

上面几种方法都可以不使用临时空间来交换两个元素,但是都有些潜在的问题,比如 越界;
所以个人觉得还是老老实实的用个临时变量吧,这样算法意图就比较清晰了。

参考: http://blog.csdn.net/yuzhihui_no1/article/details/44339711


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值