冒泡排序(python版本)

这篇文章是我很久之前在知乎看到的,我觉得是最能把这个排序讲的这么清晰明了真不多话不多说,我暂且描述下整个排序的过程。

冒泡排序的全过程

比如给你一个列表L,如下:

[2, 4, 3, 9, 7, 5, 1, 8, 6]

首先我们将24比较,4比较大,就保持不变;43比较,4比较大,43交换位置如下:

[2, 3, 4, 9, 7, 5, 1, 8, 6]

然后49比较,保持不变;97比较,9大,97交换位置,如下:

[2, 3, 4, 7, 9, 5, 1, 8, 6]

然后95比较,9大,95交换位置,如下:

[2, 3, 4, 7, 5, 9, 1, 8, 6]

91比较,9大,91交换位置,如下:

[2, 3, 4, 7, 5, 1, 9, 8, 6]

98比较,9大,98交换位置,如下:

[2, 3, 4, 7, 5, 1, 8, 9, 6]

96比较,9大,96交换位置,如下:

[2, 3, 4, 7, 5, 1, 8, 6, 9]

至此,经过第1轮“冒泡”之后,列表中最大的数字“9”到了它该到的位置。

以此类推,那么要经过多少轮才能把这个列表中的元素全都排完呢?

如果你不知道,我们可以用一个长度为3的列表来看看:

[3, 2, 1]

① 3 > 2 => [2, 3, 1]; 3 > 1 => [2, 1, 3]; 3到此排完了

② 1 < 2 => [1, 2, 3];2到此排完了,剩下一个1,没有元素和它比较了,于是排序结束。

观察上面这个例子,3个元素列表,只需要经过2轮就能排完了,因为剩最后2个元素的时候,它们互相比较一下,这2个元素的顺序就都好了,所以当一个列表的长度为len(L)时,只需要经过len(L)-1轮,排序就结束了,于是冒泡法的第一行代码就出来了:

for i in range(len(L)-1): #只需要经过len(L)-1轮,排序即结束,i代表每一轮比较
下面再看看在每轮比较中,一共比较了多少次呢?拿刚开始的列表举例,

[2, 4, 3, 9, 7, 5, 1, 8, 6] ,经过第1轮后,这个列表变为了

[2, 3, 4, 7, 5, 1, 8, 6, 9],下一轮再比较,比到6就好了,不需要再和9比较了,对吧!所以我们发现这个规律:

第1轮,比较了len(L) - 1 = 8次;

第2轮,比较了len(L) - 2 = 7次;

第N轮,比较了len(L) - N次,于是代码又来一行:

for j in range(1, len(L)-i): #这里面的i就是当前所在的轮数,j表示每一轮要遍历的元素

#这里面range(1, len(L)-i)也可以写成range(0,len(L)-i-1),反正表示的长度是一样的,区别在于
#j的第一个值是0还是1。是0时,先得到第一个元素;是1时,先得到第二个元素。
得到遍历的元素之后,我们就要比较了,相邻的两个元素,如果前面的大于后面的,就让它们的值交换,让大的往后走,一直到这个列表中最大的元素走到列表的最后面,于是:

if L[j-1] > L[j]:   # 假设当j=1时,这里是第一个元素和第二个元素比较 
    L[j-1], L[j] = L[j], L[j-1]  # Python常用的交换变量写法

好了,我们的冒泡排序就写完了。觉得很短吗?没错,实际逻辑代码就4行。

标配代码:

L = [2, 4, 3, 9, 7, 5, 1, 8, 6]

for i in range(len(L)-1):       #只需要经过len(L)-1轮,排序即结束,i代表每一轮比较
    for j in range(1, len(L)-i):#这里面的i就是当前所在的轮数,j表示每一轮要遍历的元素
        if L[j-1] > L[j]:                # 假设当j=1时,这里是第一个元素和第二个比较
            L[j-1], L[j] = L[j], L[j-1]  # Python常用的交换变量写法 

print(L)

还可以写成如下形式,但后续的代码都以上面的为主:

L = [2, 4, 3, 9, 7, 5, 1, 8, 6]
for i in range(len(L)-1):
    for j in range(0, len(L)-i-1): #和上面一样的,只是起始索引变了
        if L[j] > L[j+1]:          #当j=0时,这里是第一个元素和第二个比较
            L[j], L[j+1] = L[j+1], L[j]
print(L)
以上就是冒泡排序的最基础的代码。

完了?还有没有可优化的地方?面前的面试官皱着眉头对你说。你必须回答:有!

想象有这么几种特殊情况情况:

第一种:当遍历一轮发现没有元素交换时,排序即可结束。

[2, 1, 4, 3, 6, 5, 8, 7, 9] 当待排序列表为这个时,经过第1轮排序,就变成了

[1, 2, 3, 4, 5, 6, 7, 8, 9] 此时列表已经完全排好序了,但是呢,程序不知道,还在准备进入第2轮排序,前后比较,1和2比,2和3比,一直到7和8比完,一个也没交换,然后紧接着又要进入第3轮了!!停,在这块是不是可以优化下,我们发现在第2轮比较一遍后,没有任何值发生交换,那是不是可以说明这轮比较的所有元素全都是有序的了,所以才不需要交换。那我们在程序中可以添加个代表是否交换的变量,不交换时值为False,如果交换了就置为True。最后每轮结束,如果值为False就说明这轮没有发生交换,没有发生任何交换就直接结束循环,退出程序,因为这个列表已经排序好了;如果值为True就说明这轮发生交换了,需要进入下一轮,但在进入下一轮遍历前,需要先将已经置为True的变量重新设置为False。如果你想明白了,请看代码:

L = [2, 4, 3, 9, 7, 5, 1, 8, 6]

for i in range(len(L)-1):
    swap = False   #每一轮都要重置一次swap的值,所以要写在这边
    for j in range(1, len(L)-i):
        if L[j-1] > L[j]:
            swap = True   #每次交换就改变swap的值
            L[j-1], L[j] = L[j], L[j-1]
    if not swap: #当swap为False时,退出循环
        break

print(L)

因为我找不到原链接地址,如果涉及侵权,立即删除

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值