[排序N大件之]冒泡排序

冒泡排序,这个作为萌新入门排序时,最最最基础(没有之一)的排序方法,但是本蒟蒻果冻居然时隔四年之后全忘了,甚至有点无法理解(????),所以一下全部内容都是本蒟蒻果冻的个人理解。

 

给出一个列表:[3, 2, 9, 7, 4, 8, 1],怎么变成有序排列?

冒泡排序是一种基于[比较]-[交换]的排序

比较:从第一个数(下标为[0])开始,相邻的两个数一次进行比较,如果前者比后者大,那么交换两个相邻的数,最后一次比较是[n-2]和[n-1]下标的元素

所以第一趟比较的次数是多少:n-1,其中n是待排序的列表的大小

那么最后一趟比较的次数是多少:1,就是比较[2]和[1]的元素

可见冒泡排序一共要比较n-1趟

所以以上两条的趟数确定了冒泡循环的外层循环:for ps in range(n - 1, 0, -1) ----------注意了!!python的range是一个左闭右开的区间,所以真正的区间为[n-1, 1]

这里倒着取,完全是为了比较的方便

 

外内循环有了,内存循环呢?

冒泡排序和其他的垃圾排序(选择排序,插入排序:时间复杂度为O(n2))有一点不同,后两者部分有序的排列维持在列表的前段(通常情况,本人使用),然后一直往后扩展;

而冒泡排序,由于每一个最大的元素都像水中上浮的气泡一样,慢慢的“冒”到列表的末尾,因此,对于冒泡排序来说,部分有序的排列,维持在列表的后部分,所以就要对于部分有序排列部分的之前的元素进行比较排序

观察没一趟比较的元素,可以看出,对于每一趟比较:

  • 第一趟比较的前者元素下标从0到n-2,而后者元素是前者的+1(n-1),第一趟比较交换结束后,最大值元素已经在[n-1]就位了
  • 第二趟比较的元素前者下标从0到n-3,而后者元素是前者的+1(n-2),第二趟比较交换结束后,第二大元素已经在[n-2]就位了
  • 最后一次比较的元素前者下标为0,后者下标为1,到这里这个列表都排序完成

所以每一趟比较元素的下标范围,正好是外争循环的趟数-1(ps - 1)--------------这里注意了!!由于python新手友好,range右边取不到,所以我们右括号就只要取到ps(趟数)就可以了!!!

内层循环:for i in range(ps):

两重循环有了,剩下的该干嘛干嘛,交换两个元素总该会了吧

def bubbleSort(nums):

    n = len(nums)

    for ps in range(n - 1, 0, -1):
        for i in range(ps):
            if nums[i] > nums[i + 1]:
                nums[i], nums[i + 1] = nums[i + 1], nums[i]

    return nums

if __name__ == "__main__":
    numbers = [3, 2, 9, 7, 4, 8, 1]
    print(bubbleSort(numbers))

 

但是冒泡排序作为三大垃圾排序之首,它可以进行优化,需要一个flag(exchange),优化的基本思想就是:如果这一趟没有出现元素交换,就说明已经排序好了,就没有继续比较的必要了

优化代码:

def bubbleSort(nums):

    n = len(nums) - 1
    exchange = True
    while exchange and n > 0:
        exchange = False
        for i in range(n):
            if nums[i] > nums[i + 1]:
                nums[i], nums[i + 1] = nums[i + 1], nums[i]
                exchange = True

        n = n - 1

    return nums

if __name__ == "__main__":
    numbers = [3, 2, 9, 7, 4, 8, 1]
    print(bubbleSort(numbers))

 

时间复杂度:O(n2)

如果是进行优化过后的冒泡排序,那么最好的时间复杂度为O(n),对于一个已经排序好的列表,第一趟遍历列表时,发现没有交换...

空间复杂度:O(1)

 

posted @ 2020-09-23 15:47  剪剪  阅读(158)  评论(0编辑  收藏  举报