冒泡排序:python实现及优化

冒泡排序原理

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

python实现

根据冒泡排序的定义,我们可以用python代码实现

def bubble_sort(items):

    for i in range(len(items) - 1):  #i变量用来控制排序循环的次数(比如 n个数,需要进行 n-1次冒泡排序)
        for j in range(len(items) - 1 - i): #j变量控制冒泡过程,即相邻两元素比较,每次排完一次序,最后一个元素可以不参与下一次排序,所以要减去i
            if items[j] > items[j + 1]:
                items[j], items[j + 1] = items[j + 1], items[j]
        i += 1 #统计排序次数
    print('共循环%d次'% i)
    return items
    
arr = [1,2,8,4,7,5,6]
bubble_sort(arr)

运行结果如下:

共循环6次
[1, 2, 4, 5, 6, 7, 8]

可以看到,arr数组共有7个元素,于是进行了6次冒泡排序,成功得出排序数组。这是最普通的冒泡排序的算法实现,应该不难理解,但是这种写法有一个缺点: 假设现在有一个数组[6,1,2,3,4,5],当我们进行完第一次冒泡排序过程后变为[1,2,3,4,5,6],这时候,数组已经变成有序的了,程序要是再继续循环就比较浪费资源。为了解决这个问题,就引申出一些优化方法:

冒泡排序优化方法一:

上述数组[6,1,2,3,4,5]在第一次排序后已经是一个有序数组[1,2,3,4,5,6],当再次进行排序时,会发现任意两个相邻元素之间的位置都不会再变动,意味着已经排好序了。利用这个特性,我们可以在程序中添加一面“旗帜”,这面“旗帜”告诉计算机,现在相邻元素都不再变动位置了,证明已经排好序啦!,可以结束程序了!所以,我们重新指定一个新的变量,令他初始值为False,当发生位置变动时,我们令它为True,当元素不再变换位置时,我们立刻让该变量变成初始值False,退出循环程序,这样,就可以减少排序循环的次数啦!

看下优化后的冒泡排序算法代码:

def bubble_sort1(items):
    
    for i in range(len(items) - 1):
        flag = False   #设置一面‘旗帜’,用来控制程序什么时候结束
        for j in range(len(items) - 1 - i):
            if items[j] > items[j + 1]:
                items[j], items[j + 1] = items[j + 1], items[j]
                flag = True  #发生排序的动作,则赋值为True,证明未排序成功,继续循环;否则,证明排序完成,进入下一个 ‘if not flag’语句
        i += 1  
        if not flag:  #排序成功,则退出循环
            break
    print('共循环%d次'% i)   
    return items

arr = [1,2,8,4,7,5,6]
bubble_sort1(arr)

运行结果如下:

共循环3次
[1, 2, 4, 5, 6, 7, 8]

从运行结果可以看到,循环次数由原来6次变成3次,效率提升一倍哦。

冒泡排序优化方法二:

上面的写法虽然效率有所提升,但是还有一个问题,就是每次都是从左边到右边进行比较,这样效率不高,如果能 双向排序,即当一次从左向右的排序比较结束后,立马从右向左来一次排序比较。这样效率一定会更高!这其实就引申出了另外一种,基于冒泡排序改进的排序方法:搅拌排序 / 鸡尾酒排序。

看下再次优化后的代码:

def bubble_sort2(items):
    for i in range(len(items) - 1):
        flag = False
        for j in range(len(items) - 1 - i):
            if items[j] > items[j + 1]:
                items[j], items[j + 1] = items[j + 1], items[j]
                flag = True
        if flag:  #反向排序
            flag = False
            for j in range(len(items) - 2 - i, 0, -1):  
                if items[j - 1] > items[j]:
                    items[j], items[j - 1] = items[j - 1], items[j]
                    flag = True
            i += 1
        if not flag:
            break
    print('共循环%d次'% i) 
    return items

arr = [1,2,8,4,7,5,6]
bubble_sort2(arr)

看下运行结果:

共循环2次
[1, 2, 4, 5, 6, 7, 8]

果然,运行效率又得到提升了!循环次数由之前的3次变成了2次。

时间复杂度

1.若文件的初始状态是正序的,一趟扫描即可完成排序。所以,冒泡排序最好的时间复杂度为 O(n)
2.若初始文件是反序的,需要进行 n-1 趟排序。每趟排序要进行 n-i 次关键字的比较(1≤i≤n-1),且每次比较都必须移动记录三次来达到交换记录位置。在这种情况下,冒泡排序的最坏时间复杂度为 O(n2)

算法稳定性

冒泡排序就是把小的元素往前调或者把大的元素往后调。比较是相邻的两个元素比较,交换也发生在这两个元素之间。所以,如果两个元素相等,是不会再交换的;如果两个相等的元素没有相邻,那么即使通过前面的两两交换把两个相邻起来,这时候也不会交换,所以相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值