python实现改进版冒泡排序

一、冒泡排序属于经典算法,基本入门的时候都会手动编写冒泡排序,其算法思想为(以升序为例):

  1. 比较相邻的元素。如果第一个比第二个大,交换位置;

  2. 然后比较第二个和第三个元素,如果第二个比第三个大,交换位置。以此类推,对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对,此时得到最后的元素是最大的数;

  3. 一趟比较完之后,针对前面(1, n-1)个元素重复以上的步骤,最后一个元素已经排好序。

  4. 依次再针对(1,n-2 ),(1,n-3 )......(1, 2)中的元素重复上面的步骤,直到没有任何一对数字需要比较,得到升序排列

其算法代码实现如下:

def bubble_sort_1(list_sort):
    for i in range(0, len(list_sort)):
        for j in range(0, len(list_sort) - i -1):
            if list_sort[j] > list_sort[j + 1]:
                list_sort[j], list_sort[j+1] = list_sort[j+1], list_sort[j]
        i = i + 1
    print("遍历次数为:%d" % i)
    return list_sort

print(bubble_sort([5, 8, 6, 3, 9, 2, 1, 7]))

我们对[5, 8, 6, 3, 9, 2, 1, 7]进行排序,最后输出结果为[1, 2, 3, 5, 6, 7, 8 ,9], 外层的循环要遍历n次,每次遍历过程中的元素和元素的总数n相当,因此该算法的时间复杂度为O(n^2)。

二、在实际的排序情况中,会存在一些特殊的情况,比如我们对[3, 4, 2, 1, 5, 6, 7, 8]进行排序,按照我们上面的算法,第一次遍历后,序列为[3, 2, 1, 4, 5, 6, 7, 8],第二次遍历后序列为[2, 1, 3, 4, 5, 6, 7, 8] ,第三次遍历后[1, 2, 3, 4, 5, 6, 7, 8] ,按照实际情况现在的序列已经有序,不需要继续遍历比较,,但在上面的算法中还会对他们继续进行比较操作,直到n次遍历完为止。针对这种情况,我们可以设置一个交换标记,当在一次遍历过程中,没有发生元素的位置交换,说明这时候序列已经有序,则算法可以提前终止,加入元素交换标识符change, 用代码实现算法改进:

def bubble_sort_2(list_sort):
    for i in range(0, len(list_sort)):
        change = 0
        for j in range(0, len(list_sort) - i -1):
            if list_sort[j] > list_sort[j + 1]:
                list_sort[j], list_sort[j+1] = list_sort[j+1], list_sort[j]
                change = 1
        if change == 0:
            break
        i = i + 1
    print("遍历次数为:%d" % i)
    return list_sort

print(bubble_sort_2([5, 8, 6, 3, 9, 2, 1, 7]))

两个版本对相同的数列进行比较,外层的遍历次数分别为8次和6次。

遍历次数为:8
[1, 2, 3, 5, 6, 7, 8, 9]
遍历次数为:6
[1, 2, 3, 5, 6, 7, 8, 9]

每一次遍历后的序列如下输出所示:

[5, 6, 3, 8, 2, 1, 7, 9]
[5, 3, 6, 2, 1, 7, 8, 9]
[3, 5, 2, 1, 6, 7, 8, 9]
[3, 2, 1, 5, 6, 7, 8, 9]
[2, 1, 3, 5, 6, 7, 8, 9]
[1, 2, 3, 5, 6, 7, 8, 9]
[1, 2, 3, 5, 6, 7, 8, 9]
[1, 2, 3, 5, 6, 7, 8, 9]
遍历次数为:8
[5, 6, 3, 8, 2, 1, 7, 9]
[5, 3, 6, 2, 1, 7, 8, 9]
[3, 5, 2, 1, 6, 7, 8, 9]
[3, 2, 1, 5, 6, 7, 8, 9]
[2, 1, 3, 5, 6, 7, 8, 9]
[1, 2, 3, 5, 6, 7, 8, 9]
遍历次数为:6

从每次遍历详细的序列输出可以看到,用第一种方法遍历到第6次后,序列已经为有序,但是遍历还会继续直到8次结束,而对于加入标识符改进的第二种方法,发现在第6次已经没有进行元素交换后,遍历立即停止,不再继续进行。

三、对于某些序列我们可以做进一步优化,比如对于序列[3, 4, 2, 1, 5, 6, 7, 8],后半部分[5, 6, 7, 8]已经排序好,我们先用前两种方法进行排序,可以看到输出结果:

[3, 2, 1, 4, 5, 6, 7, 8]
[2, 1, 3, 4, 5, 6, 7, 8]
[1, 2, 3, 4, 5, 6, 7, 8]
[1, 2, 3, 4, 5, 6, 7, 8]
[1, 2, 3, 4, 5, 6, 7, 8]
[1, 2, 3, 4, 5, 6, 7, 8]
[1, 2, 3, 4, 5, 6, 7, 8]
[1, 2, 3, 4, 5, 6, 7, 8]
遍历次数为:8
[3, 2, 1, 4, 5, 6, 7, 8]
[2, 1, 3, 4, 5, 6, 7, 8]
[1, 2, 3, 4, 5, 6, 7, 8]
遍历次数为:3

第一种方法依然遍历了8次,第二种方法只遍历了3次就提前结束了。但是在每次遍历的过程种,虽然[5, 6, 7, 8]已经有序了,但是还依然需要参与相邻元素的两两比较,对于这种情况我们可以找到序列有序区的边界,在每一次遍历的内部比较和元素交换过程中,最后一次元素交换的位置的右边是有序的元素序列,对于已经有序的序列,我们在每次遍历的过程中不必再去做比较操作,加入边界记录符sorted_border,内层循环 j 的迭代边界由len(list_sort) - i -1改为sorted_border,算法改进如下:

def bubble_sort_3(list_sort):
    print("-"*120)
    last_change_index = 0
    sorted_border = len(list_sort) - 1
    for i in range(0, len(list_sort)):
        change = 0
        for j in range(0, sorted_border):
            if list_sort[j] > list_sort[j + 1]:
                list_sort[j], list_sort[j+1] = list_sort[j+1], list_sort[j]
                last_change_index = j
                change = 1
            print("j的值为:%d" % j, end="   ")
        sorted_border = last_change_index
        if change == 0:
            break
        i = i + 1
        print(list_sort)
    print("结束")
    return list_sort

bubble_sort_3([3, 4, 2, 1, 5, 6, 7, 8])

用第二种方法排序此数列和第三种方法进行比较,输出结果如下:

j的值为:0   j的值为:1   j的值为:2   j的值为:3   j的值为:4   j的值为:5   j的值为:6   [3, 2, 1, 4, 5, 6, 7, 8]
j的值为:0   j的值为:1   j的值为:2   j的值为:3   j的值为:4   j的值为:5   [2, 1, 3, 4, 5, 6, 7, 8]
j的值为:0   j的值为:1   j的值为:2   j的值为:3   j的值为:4   [1, 2, 3, 4, 5, 6, 7, 8]
j的值为:0   j的值为:1   j的值为:2   j的值为:3   结束
------------------------------------------------------------------------------------------------------------------------
j的值为:0   j的值为:1   j的值为:2   j的值为:3   j的值为:4   j的值为:5   j的值为:6   [3, 2, 1, 4, 5, 6, 7, 8]
j的值为:0   j的值为:1   [2, 1, 3, 4, 5, 6, 7, 8]
j的值为:0   [1, 2, 3, 4, 5, 6, 7, 8]
结束

从输出结果可以看出,第一次遍历过程种元素比较的次数相同,j 的值都为6,结束第一趟遍历后,第三种方法由于记录了最后一个交换元素的索引,即索引为2的元素值和它后面紧邻索引为3的元素值4进行交换,[5, 6, 7, 8]已经有序了并没有进行交换操作。因此,在第二次的遍历过程种,第二种算法 j 的值为5,而第三种算法种 j 的值减小到1就结束比较操作了,后面的两趟遍历中,第三种算法比较的次数明显少于第二种算法。 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值