算法笔记:冒泡排序

Posted UQI-LIUWJ

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法笔记:冒泡排序相关的知识,希望对你有一定的参考价值。

1 最基本的冒泡排序

冒泡排序(Bubble Sort)是排序算法里面比较简单的一个排序。它重复地遍历要排序的数列,一次比较两个数据元素,如果顺序不对则进行交换,并一直重复这样的走访操作,直到没有要交换的数据元素为止。

1.1 算法举例

  • 比如有一个序列:1、5、4、2、6、3,我们要将它按从小到大排序。

  • 按照冒泡排序的思想,我们要把相邻的元素两两比较,根据大小来交换元素的位置
轮次操作内容

第一轮

(右边每一格是一小步)

比较1和5,1比5小,顺序正确,元素位置不变

154263

比较5和4,5比4大,顺序错误,交换元素位置

154263

 ——>

145263

比较5和2,5比2大,顺序错误,交换元素位置

145263

——>

142563

比较5和6,5比6小,顺序正确,元素位置不变

142563

比较6和3,6比3大,顺序错误,交换元素位置

142563

——>

142536

第二轮

比较1~3即可,因为最后的6已经是有序的了

最后的结果是

124356

第三轮

比较1~3 即可,因为最后的5,6已经是有序的了

最后的结果是

123456
第四轮

比较1~3即可,因为最后的4、5、6已经是有序的了

最后的结果是 【注意这一轮没有任何更新!也就是说,第四轮是没有作用的轮次!】

123456
第五轮

比较1~2即可,因为后面的都是有序的了

最后的结果是 【注意这一轮没有任何更新!也就是说,第四轮是没有作用的轮次!】

123456

 1.2 代码实现(python)

lst=[1,5,4,2,6,3]


for i in range(len(lst)):
    for j in range(len(lst)-i-1):
        #i 表示多少个元素已经排序好了,一开始是0个,最终是len-1个,也即i<len
        
        #每一步是j和j+1 进行比较,所以j+1的范围是:j+1 <len-i,也即j<len-i-1
        
        if(lst[j]>lst[j+1]):
            tmp=lst[j+1]
            lst[j+1]=lst[j]
            lst[j]=tmp
            #如果比较的两个元素顺序错误,那么交换两个元素的顺序
            
lst
# [1, 2, 3, 4, 5, 6]

2  算法优化1(添加已排序标记)

  • 从1.1的表格我们不难发现,当第三轮结束的时候,其实已经排序好了。第四第五轮是冗余的遍历。我们可以考虑将其去掉。
  • 在这里,我们创立一个“已排序”标记。如果在某一轮,没有发生一次换位,那么说明所有元素都已经排序完成,那么就可以结束算法了
  • 比如上图,在第四轮的过程中,发现已经没有顺序的交换了,所以结束算法。

2.1 代码实现(python)

lst=[1,5,4,2,6,3]


for i in range(len(lst)):
    flag_over=True
    #表示某一轮是否已经全部排序完成
    #如果有元素交换,那么flag_over应该是False,如果没有元素交换,那么flag_over会一直是True
    for j in range(len(lst)-i-1):
        #i 表示多少个元素已经排序好了,一开始是0个,最终是len-1个,也即i<len
        
        #每一步是j和j+1 进行比较,所以j+1的范围是:j+1 <len-i,也即j<len-i-1
        
        if(lst[j]>lst[j+1]):
            tmp=lst[j+1]
            lst[j+1]=lst[j]
            lst[j]=tmp
            #如果比较的两个元素顺序错误,那么交换两个元素的顺序
            flag_over=False
            #发生了元素交换,说明至少在这一轮,整个序列还没有排序完成
    
    if(flag_over==True):
        break
            
            
lst
#[1, 2, 3, 4, 5, 6]

3 算法优化2(每次不一定只往前一格)

  • 有的情况下,一轮结束了,可能末尾好几个点都排序好了,那么再一轮一轮地遍历这些点也是不合适的,所以优化方向2是记录一下某一轮最后一个没有排序好的点的位置
  • 改进方法是,每次交换后,记录一下交换的位置。每轮最后一个交换的位置就是下一次lst[j]需要遍历到的最后一个位置【因为后面的位置都没有发生交换了,也就是已经排序完成了】

3.1 代码实现

lst=[1,5,4,2,6,3]


for i in range(len(lst)):
    flag_over=True
    #表示某一轮是否已经全部排序完成
    #如果有元素交换,那么flag_over应该是False,如果没有元素交换,那么flag_over会一直是True
    
    j_end_index=len(lst)-i-1
    #每一轮比较的j坐标的末尾坐标
    
    tmp_j_end=0
    
    for j in range(j_end_index):
        #i 表示多少个元素已经排序好了,一开始是0个,最终是len-1个,也即i<len
        
        #每一步是j和j+1 进行比较,所以j+1的范围是:j+1 <len-i,也即j<len-i-1
        
        if(lst[j]>lst[j+1]):
            tmp=lst[j+1]
            lst[j+1]=lst[j]
            lst[j]=tmp
            #如果比较的两个元素顺序错误,那么交换两个元素的顺序
            flag_over=False
            #发生了元素交换,说明至少在这一轮,整个序列还没有排序完成
            
            tmp_j_end=j
            #每一次交换后,记录一下发生交换的位置
        
    j_end_index=tmp_j_end
    #这一轮最后一次交换所在的位置,就是下一轮j需要遍历到的位置
    #因为后续位置的元素都已经排序完成了
    
    if(flag_over==True):
        break
            
            
lst
#[1, 2, 3, 4, 5, 6]

实现了j_end_index之后,甚至flag_over都不用了。因为如果某一轮内没有发生交换,那么tmp_j_end就是默认的0,那么下一轮j的取值范围就是range(0),空集合

4 冒泡排序复杂度

4.1 时间复杂度


  • 最差时间复杂度:元素正好倒序,每一轮只能少遍历一个元素,复杂度是
  • 最好时间复杂度:元素正序,一轮搞定,复杂度O(N)

4.2 空间复杂度

只需要一个进行元素交换的额外空间,复杂度是O(1)

以上是关于算法笔记:冒泡排序的主要内容,如果未能解决你的问题,请参考以下文章

鸡尾酒算法排序

冒泡排序之go语言实现

算法通关手册 刷题笔记2 数组排序之冒泡排序选择排序

[AI助力] 算法通关手册 刷题笔记2 数组排序之冒泡排序选择排序

数据结构与算法笔记—— 冒泡排序

算法笔记:冒泡排序