时间复杂度O(N^2)级排序算法

187 阅读1分钟

- 冒泡排序

关键词:两两交换

① 初级算法

def bubbleSort(nums):
    n = len(nums)
    for i in range(n - 1):
        for j in range(1, n - i):
            if nums[j - 1] > nums[j]:
                nums[j - 1], nums[j] = nums[j], nums[j - 1]
    return nums

② 优化手段: 当本地循环未发生任何的交换时,则认为数组已经有序,无需继续遍历

def bubbleSort(nums):
    n = len(nums)
    for i in range(n - 1):
        flag = False
        for j in range(n - i - 1):
            if nums[j] > nums[j + 1]:
                flag = True
                nums[j], nums[j + 1] = nums[j + 1], nums[j]
        if not flag: # 未交换
            break
    return nums

③ 优化手段: 记录每次遍历中最后交换的元素index,下次遍历时无需再进行到 n - i的位置

def bubbleSort(nums):
    n = len(nums)
    indexOfLastUnsortedIndex = n - 1
    swipped = True
    swippedIndex = -1
    while swipped:
        swipped = False
        for index in range(indexOfLastUnsortedIndex):
            if nums[index] < nums[index + 1]:
                nums[index], nums[index + 1] = nums[index + 1], nums[index]
                swipped = True
                swippedIndex = index
        indexOfLastUnsortedIndex = swippedIndex
    return nums 

稳定的排序算法

时间复杂度: 以上的优化手段,最好的情况下只需要O(n)的时间复杂度(数组已有序的情况下),但平均时间复杂度仍然是O(n^2).

空间复杂度: O(1)。

- 选择排序

关键词: 每轮选择一个最值

① 初级算法

def selectionSort(nums):
    n = len(nums)
    for i in range(n - 1):
        minIndex = i 
        for j in range(i + 1, n):
            if nums[j] < nums[minIndex]:
                minIndex = j 
        nums[i], nums[minIndex] = nums[minIndex], nums[i]
    return nums 

② 优化手段: 二元选择,每轮同时选择最大值和最小值

def selectionSort(nums):
    n = len(nums)
    # 外层遍历
    for i in range(n // 2):
        minIndex, maxIndex = i, i
        for j in range(i + 1, n - i):
            if nums[j] > nums[maxIndex]:
                maxIndex = j 
            if nums[j] < nums[minIndex]:
                minIndex = j 
        // 相等表示: 此时后续位置已经处于"平均值",无需再排序
        if minIndex == maxIndex: break
        # min
        nums[minIndex], nums[i] = nums[i], nums[minIndex]
        # max
        if maxIndex == i: maxIndex = minIndex
        nums[maxIndex], nums[n - i - 1] = nums[n - i - 1], nums[maxIndex]
    return nums

在外层遍历中,只需要遍历 n//2 次。这是因为每轮都会查找到两个最值,而且无需考虑奇偶数情况(因为如果处于奇数,其他元素都排好序了剩余的一个元素一定是"被迫"有序)。

不稳定的排序算法

时间复杂度: 优化后的算法平均时间复杂度仍然为O(n^2)

空间复杂度: O(1)

- 插入排序

关键词: 将index元素插入前置已排好序的数组中

① 交换法: 不断的与前面数字交换,直到找到合适的位置

def insertSort(nums):
    n = len(nums)
    # 外层遍历: 从第二个元素开始
    for i in range(1, n):
        j = i - 1
        while j >= 0 and nums[j] > nums[j + 1]:
            # 直接替换元素
            nums[j], nums[j + 1] = nums[j + 1], nums[j]
            j -= 1
    return nums 

② 移动法: 不断的比较,前面的数字向后挪出位置,然后找到后一举插入

def insertSort(nums):
    n = len(nums)
    for i in range(1, n):
        cur = nums[i]
        j = i - 1
        while j >= 0 and nums[j] > cur:
            nums[j + 1] = nums[j]
            # 每次循环,其实都是在准确位置的前一个位置
            j -= 1
        nums[j + 1] = cur 
    return nums

稳定的排序算法

空间复杂度: O(1)