当前位置:   article > 正文

python实现改进版冒泡排序_改进的冒泡排序pathony

改进的冒泡排序pathony

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

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

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

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

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

其算法代码实现如下:

  1. def bubble_sort_1(list_sort):
  2. for i in range(0, len(list_sort)):
  3. for j in range(0, len(list_sort) - i -1):
  4. if list_sort[j] > list_sort[j + 1]:
  5. list_sort[j], list_sort[j+1] = list_sort[j+1], list_sort[j]
  6. i = i + 1
  7. print("遍历次数为:%d" % i)
  8. return list_sort
  9. 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, 用代码实现算法改进:

  1. def bubble_sort_2(list_sort):
  2. for i in range(0, len(list_sort)):
  3. change = 0
  4. for j in range(0, len(list_sort) - i -1):
  5. if list_sort[j] > list_sort[j + 1]:
  6. list_sort[j], list_sort[j+1] = list_sort[j+1], list_sort[j]
  7. change = 1
  8. if change == 0:
  9. break
  10. i = i + 1
  11. print("遍历次数为:%d" % i)
  12. return list_sort
  13. print(bubble_sort_2([5, 8, 6, 3, 9, 2, 1, 7]))
'
运行

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

  1. 遍历次数为:8
  2. [1, 2, 3, 5, 6, 7, 8, 9]
  3. 遍历次数为:6
  4. [1, 2, 3, 5, 6, 7, 8, 9]
'
运行

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

  1. [5, 6, 3, 8, 2, 1, 7, 9]
  2. [5, 3, 6, 2, 1, 7, 8, 9]
  3. [3, 5, 2, 1, 6, 7, 8, 9]
  4. [3, 2, 1, 5, 6, 7, 8, 9]
  5. [2, 1, 3, 5, 6, 7, 8, 9]
  6. [1, 2, 3, 5, 6, 7, 8, 9]
  7. [1, 2, 3, 5, 6, 7, 8, 9]
  8. [1, 2, 3, 5, 6, 7, 8, 9]
  9. 遍历次数为:8
  10. [5, 6, 3, 8, 2, 1, 7, 9]
  11. [5, 3, 6, 2, 1, 7, 8, 9]
  12. [3, 5, 2, 1, 6, 7, 8, 9]
  13. [3, 2, 1, 5, 6, 7, 8, 9]
  14. [2, 1, 3, 5, 6, 7, 8, 9]
  15. [1, 2, 3, 5, 6, 7, 8, 9]
  16. 遍历次数为:6
'
运行

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

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

  1. [3, 2, 1, 4, 5, 6, 7, 8]
  2. [2, 1, 3, 4, 5, 6, 7, 8]
  3. [1, 2, 3, 4, 5, 6, 7, 8]
  4. [1, 2, 3, 4, 5, 6, 7, 8]
  5. [1, 2, 3, 4, 5, 6, 7, 8]
  6. [1, 2, 3, 4, 5, 6, 7, 8]
  7. [1, 2, 3, 4, 5, 6, 7, 8]
  8. [1, 2, 3, 4, 5, 6, 7, 8]
  9. 遍历次数为:8
  10. [3, 2, 1, 4, 5, 6, 7, 8]
  11. [2, 1, 3, 4, 5, 6, 7, 8]
  12. [1, 2, 3, 4, 5, 6, 7, 8]
  13. 遍历次数为:3
'
运行

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

  1. def bubble_sort_3(list_sort):
  2. print("-"*120)
  3. last_change_index = 0
  4. sorted_border = len(list_sort) - 1
  5. for i in range(0, len(list_sort)):
  6. change = 0
  7. for j in range(0, sorted_border):
  8. if list_sort[j] > list_sort[j + 1]:
  9. list_sort[j], list_sort[j+1] = list_sort[j+1], list_sort[j]
  10. last_change_index = j
  11. change = 1
  12. print("j的值为:%d" % j, end=" ")
  13. sorted_border = last_change_index
  14. if change == 0:
  15. break
  16. i = i + 1
  17. print(list_sort)
  18. print("结束")
  19. return list_sort
  20. bubble_sort_3([3, 4, 2, 1, 5, 6, 7, 8])
'
运行

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

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/824408
推荐阅读
相关标签
  

闽ICP备14008679号