搜索和排序(2) - 冒泡排序、选择排序和插入排序

1,791 阅读3分钟

冒泡排序

冒泡排序要经过多次遍历列表,她比较相邻的元素,将不合顺序的进行位置交换,在每一轮遍历中都将下一个最大值放在正确的位置上。

下图展示了冒泡排序第一次遍历的过程,其中深色的是正在比较的元素。如果列表中有n个元素,那么第一轮遍历要比较n-1对:

image.png 当第二轮开始遍历时,最大值已经在正确的位置上了,所以还剩n-1个元素需要遍历,那么第二遍就是要遍历n-2次。以此类推,那么我们需要遍历的轮数就是n-1轮。当n-1轮完成后,最小的元素就必然在正确的位置上了。

20230514155125231.GIF

用Python实现冒泡排序

def bubbleSort(alist):
    for passnum in range(len(alist) - 1, 0, -1):
        for i in range(passnum):
            if alist[i] > alist[i + 1]
                temp = alist[i]
                alist[i] = alist[i + 1]
                alist[i + 1] = temp

冒泡排序通常认为是效率最低的排序算法,因为在确定最终的位置前必须交换元素。所以我们可以通过在一轮遍历中有没有发生元素交换,如果没有,证明列表已经有序,下一次遍历就不需要将这两个元素再进行一次排序了,这种对冒泡排序的修改成为短冒泡

def shortBubbleSort(alist):
    exchanges = True
    passnum = len(alist - 1)
    while passnum > 0 and exchanges:
        exchanges = False
        for i in range(passnum):
            if alist[i] > alist[i + 1]:
                exchanges = True
                temp = alist[i]
                alist[i] = alist[i + 1]
                alist[i + 1] = temp
        passnum = passnum + 1

选择排序

选择排序是在冒泡排序的基础上做了改进,每次遍历列表时只做一次交换。它是在每一次遍历时找到元素最大值并放在正确位置上,假设我们给n个元素排序,那么需要遍历n-1轮。

image.png 20230514155737156.GIF

用Python实现选择排序

def selectionSort(alist):
    for fillslot in range(len(alist) - 1, 0, -1):
        positionOfMax = 0
        for location in range(1, fillslot + 1):
            if alist[location] > alist[positionOfMax]:
                positionOfMax = location
        temp = alist[fillslot]
        alist[fillslot] = alist[posotionOfMax]
        alist[positionOfMax] = temp

选择排序的时间复杂度也是O(n²),但是由于减少了交换次数,所以选择排序通常更快。

插入排序

插入排序的时间复杂度也是O(n²),它是在列表较低的一段维护一个有序的子列表,将每个新元素逐个插入子列表中。

image.png

下图详细的展示了第5轮遍历的情况。此时,有序子列表中包含5个元素:17、26、54、77、93,现在想插入31。第一次与93比较,93右移,同理77和54也会右移。当遇到26时不会移动了,所以31的位置就找到了,现在子列表中就有6个元素了:

image.png 所以,当n个元素排序时,插入排序需要遍历n-1轮,循环从位置1开始,直到n-1结束,这些元素都被插入到有序子列表中。

20230514155749332.GIF

用Python实现插入排序

def insertionSort(alist):
    for index in range(1, len(alist)):
        currentValue = alist[index]
        position = index
        while position > 0 and alist[position - 1] > currentValue:
            alist[position] = alist[position - 1] // 实现了移动操作,将列表中的一个值挪一个位置,为待插入元素腾出空间
            position = position - 1
        alist[position] = currentValue

最坏情况下,插入排序算法的比较次数是前n-1个整数之和,对应的时间复杂度的是O(n²);最好的情况下,列表已经是有序的,那么每一轮只需比较一次。