Python_072501经典算法--冒泡排序--个人理解(更新)

265 阅读4分钟

@TOC

冒泡排序(BubbleSort)

冒泡排序(BubbleSort)以其,''在排序过程中相邻元素不断交换,某些元素慢慢被换到最后,看起来就像是元素在冒泡一样''而得名,是一种简单的基于关键词比较的排序算法。

算法原理

冒泡排序的原理(以递减序为例)是每次从头开始依次比较相邻的两个元素,如果后面一个元素比前一个要大,说明顺序不对,则将它们交换,本次循环完毕之后再次从头开始扫描,直到某次扫描中没有元素交换,说明每个元素都比它后面的元素大,至此排序完成。

时间复杂度

若文件的初始状态是排好序的的,计算机扫描即可完成排序。所需的关键字比较次数C和记录移动次数 M 均达到最小值(Cmin = n-1, Mmin = 0)

冒泡排序最好的时间复杂度为O(N)。

(不懂没关系,先有个概念,待会看例子就OK了)

若初始数据是反序的,需要进行N趟排序。每趟排序要进行 C = N-1次关键字的比较(1≤i≤N-1)和总共(Mmax = (N*(N-1))/2)次的移动(移动次数由乱序对的个数决定,即多少对元素顺序不对,如 1 3 4 2 5 ),在这种情况下,比较和移动次数均达到最大值(Cmax =N*(N-1) + Mmax=(N*(N-1))/2 = O(N2)。所以,冒泡排序的最坏时间复杂度为O(N2)

(不懂没关系,先有个概念,待会看例子就OK了)

举个栗子

排序规律万万种,我就用简单的数字大小来说明吧~(当然主要应用是其他复杂类型的比较)

一组数1 2 3 4 5,最后按照从大到小排列(其他类型的数据就是别的规律排列),则排列后就是5 4 3 2 1

1 2 3 4 5 ----> 5 4 3 2 1

第1个3步 2 1 3 4 5 这里是三次运算!

为什么是三次!(扫描,对比1 2一次,交换1 2一次!)不理解的话,八成你没有用机器思维去思考,计算机是0 1运算,判断运算时间的时候,你要把每个操作拆解成最最最基础的操作。

第2个3步 2 3 1 4 5

第3个3步 2 3 4 1 5

第4个3步 2 3 4 5 1 好了最后一位,已经是最小的了

第5个3步 3 2 4 5 1

第6个3步 3 4 2 5 1

第7个3步 3 4 5 2 1 好了最后两位

第8个3步 4 3 5 2 1

第9个3步 4 5 3 2 1 好了最后三位

第10个3步 5 4 3 2 1 好了最后四位 同时间因为只剩一位,所以最后五位都ok

用的次数为,3*(4+3+2+1+0)----跟数据数量n联系一下,就是1.5n(n-1),求极限是1.5n**2

但是在算法复杂度里面,我们是以运行的循环次数计算

举个栗子

for:
	pass
	for:
		pass

这样的我们就说复杂度为N**2

所以冒泡排序最好的时间复杂度为O(N),最坏时间复杂度为O(N**2)

算法改进

第一种是上浮操作与下沉操作相结合。传统的冒泡排序只有上浮操作,如果碰到一些很特殊的数据就会显得笨一点,例如(2、3、4、5、1)这个数列按增序排列,那么按照普通冒泡算法就要扫描5趟,可是我们一眼就看出来直接把 1 挪到第一个就行了,扫描 5 次实在是太笨了,于是我们在每次上浮操作后加上一个下沉操作,这样就更快了。

第二中改进是减少无效比较的次数。所谓无效比较就是当我们已知结果却还要去比较。如果我们多观察冒泡排序的中间过程,我们就会发现,末尾的一些元素在一定次数的扫描后已经到达最终位置了(因为每次扫描后都至少会有一个新的元素到达最终位置),再比较就会造成无效比较。改进方法是,记录下每次扫描中发生交换的最后一个元素位置,下一次扫描就到这里为止。

可是,无论怎么改进,冒泡排序的时间复杂度都是O(N^2)哈哈哈

最后给个冒泡的代码吧

def bubble_sort(numberlist):
    '''冒泡排序'''
    n = len(numberlist)
    for j in range(n-1):
    	# 这边原本是n-1,改为n-1-j是优化过的
        for i in range(0, n-1-j):
            if numberlist[i] > numberlist[i+1]:
                numberlist[i],numberlist[i+1] = numberlist[i+1],numberlist[i]

if __name__ == '__main__':
    li = [2, 9, 3, -5, 0, 100, 60]
    print(li)
    bubble_sort(li)
    print(li)