常见排序算法

271 阅读5分钟

以下是 常见排序算法 的详细整理,涵盖原理、时间复杂度、稳定性及代码实现(Python示例),附对比总结表:


1. 基础排序算法

(1) 冒泡排序(Bubble Sort)

  • 原理:依次比较相邻元素,将较大的元素“冒泡”到右侧。

  • 时间复杂度:平均和最坏 O(n²),最好 O(n)(已排序时)。

  • 稳定性:稳定。

  • 代码

    
    def bubble_sort(arr):
    
        n = len(arr)
    
        for i in range(n):
    
            swapped = False
    
            for j in range(0, n-i-1):
    
                if arr[j] > arr[j+1]:
    
                    arr[j], arr[j+1] = arr[j+1], arr[j]
    
                    swapped = True
    
            if not swapped:  # 提前终止优化
    
                break
    
        return arr
    
    

(2) 选择排序(Selection Sort)

  • 原理:每次从未排序部分选择最小元素,放到已排序末尾。

  • 时间复杂度:始终 O(n²)

  • 稳定性:不稳定(交换可能破坏顺序)。

  • 代码

    
    def selection_sort(arr):
    
        n = len(arr)
    
        for i in range(n):
    
            min_idx = i
    
            for j in range(i+1, n):
    
                if arr[j] < arr[min_idx]:
    
                    min_idx = j
    
            arr[i], arr[min_idx] = arr[min_idx], arr[i]
    
        return arr
    
    

(3) 插入排序(Insertion Sort)

  • 原理:将未排序元素逐个插入已排序部分的正确位置。

  • 时间复杂度:平均和最坏 O(n²),最好 O(n)

  • 稳定性:稳定。

  • 代码

    
    def insertion_sort(arr):
    
        for i in range(1, len(arr)):
    
            key = arr[i]
    
            j = i-1
    
            while j >=0 and key < arr[j]:
    
                arr[j+1] = arr[j]
    
                j -= 1
    
            arr[j+1] = key
    
        return arr
    
    

2. 高效排序算法

(1) 快速排序(Quick Sort)

  • 原理:分治法,选取基准(pivot),将小于基准的放左边,大于的放右边,递归处理子数组。

  • 时间复杂度:平均 O(n log n),最坏 O(n²)(已排序时,若基准选择不当)。

  • 稳定性:不稳定。

  • 代码

    
    def quick_sort(arr):
    
        if len(arr) <= 1:
    
            return arr
    
        pivot = arr[len(arr)//2]  # 基准选择中间元素
    
        left = [x for x in arr if x < pivot]
    
        middle = [x for x in arr if x == pivot]
    
        right = [x for x in arr if x > pivot]
    
        return quick_sort(left) + middle + quick_sort(right)
    
    

(2) 归并排序(Merge Sort)

  • 原理:分治法,递归分割数组至单个元素,再合并有序子数组。

  • 时间复杂度:始终 O(n log n)

  • 稳定性:稳定。

  • 代码

    
    def merge_sort(arr):
    
        if len(arr) <= 1:
    
            return arr
    
        mid = len(arr) // 2
    
        left = merge_sort(arr[:mid])
    
        right = merge_sort(arr[mid:])
    
        return merge(left, right)
    
    
    
    def merge(left, right):
    
        res = []
    
        i = j = 0
    
        while i < len(left) and j < len(right):
    
            if left[i] <= right[j]:
    
                res.append(left[i])
    
                i += 1
    
            else:
    
                res.append(right[j])
    
                j += 1
    
        res.extend(left[i:])
    
        res.extend(right[j:])
    
        return res
    
    

(3) 堆排序(Heap Sort)

  • 原理:将数组构建为大顶堆,依次取出堆顶元素(最大值)并调整堆。

  • 时间复杂度:始终 O(n log n)

  • 稳定性:不稳定。

  • 代码

    
    def heap_sort(arr):
    
        def heapify(arr, n, i):
    
            largest = i
    
            left = 2*i + 1
    
            right = 2*i + 2
    
            if left < n and arr[left] > arr[largest]:
    
                largest = left
    
            if right < n and arr[right] > arr[largest]:
    
                largest = right
    
            if largest != i:
    
                arr[i], arr[largest] = arr[largest], arr[i]
    
                heapify(arr, n, largest)
    
    
    
        n = len(arr)
    
        # 构建大顶堆
    
        for i in range(n//2-1, -1, -1):
    
            heapify(arr, n, i)
    
        # 逐个提取元素
    
        for i in range(n-1, 0, -1):
    
            arr[i], arr[0] = arr[0], arr[i]
    
            heapify(arr, i, 0)
    
        return arr
    
    

3. 非比较排序

(1) 计数排序(Counting Sort)

  • 适用场景:整数排序,且数据范围 k 较小(如 0~100)。

  • 时间复杂度O(n + k)k 为数据范围。

  • 稳定性:稳定。

  • 代码

    
    def counting_sort(arr):
    
        max_val = max(arr)
    
        count = [0] * (max_val + 1)
    
        for num in arr:
    
            count[num] += 1
    
        res = []
    
        for i in range(len(count)):
    
            res.extend([i] * count[i])
    
        return res
    
    

(2) 基数排序(Radix Sort)

  • 原理:按位数从低位到高位依次进行稳定排序(通常用计数排序)。

  • 时间复杂度O(d(n + k))d 为最大位数,k 为基数(如10进制时为10)。

  • 稳定性:稳定。

  • 代码

    
    def radix_sort(arr):
    
        max_num = max(arr)
    
        exp = 1
    
        while max_num // exp > 0:
    
            counting_sort_by_digit(arr, exp)
    
            exp *= 10
    
        return arr
    
    
    
    def counting_sort_by_digit(arr, exp):
    
        n = len(arr)
    
        output = [0] * n
    
        count = [0] * 10
    
        for num in arr:
    
            digit = (num // exp) % 10
    
            count[digit] += 1
    
        for i in range(1, 10):
    
            count[i] += count[i-1]
    
        for i in range(n-1, -1, -1):
    
            digit = (arr[i] // exp) % 10
    
            output[count[digit]-1] = arr[i]
    
            count[digit] -= 1
    
        for i in range(n):
    
            arr[i] = output[i]
    
    

对比总结表

算法平均时间复杂度最坏时间复杂度空间复杂度稳定性适用场景
冒泡排序O(n²)O(n²)O(1)稳定教学或小规模数据
选择排序O(n²)O(n²)O(1)不稳定简单实现,非主流应用
插入排序O(n²)O(n²)O(1)稳定小规模或基本有序数据
快速排序O(n log n)O(n²)O(log n)不稳定通用排序,平均性能最优
归并排序O(n log n)O(n log n)O(n)稳定大数据、外部排序、链表排序
堆排序O(n log n)O(n log n)O(1)不稳定原地排序,内存受限场景
计数排序O(n + k)O(n + k)O(n + k)稳定整数且范围小(如年龄、分数)
基数排序O(d(n + k))O(d(n + k))O(n + k)稳定多关键字整数(如手机号)

应用建议

  1. 通用场景:优先选择快速排序(需随机化基准避免最坏情况)。

  2. 稳定性要求:选择归并排序或计数/基数排序。

  3. 内存受限:堆排序(原地排序,无需额外空间)。

  4. 小规模数据:插入排序(常数因子小,实际更快)。


学习资源

  1. 书籍:《算法导论》(第2章、第6-8章)、《算法(第4版)》。

  2. 刷题:LeetCode 912. 排序数组56. 合并区间

  3. 可视化工具Visualgo 动态演示排序过程。

掌握排序算法是理解算法设计与分析的基础,建议通过手写代码和复杂度分析加深理解!