跳转至

排序算法完全指南

重要性:⭐⭐⭐⭐⭐ 学习时间:1-2周 前置知识:数组、复杂度分析


📚 目录

  1. 排序算法总览
  2. 初级排序算法
  3. 高级排序算法
  4. 特殊排序算法
  5. 排序算法选择
  6. LeetCode题目

排序算法总览

排序算法比较图

算法对比表

算法 平均时间 最坏时间 最好时间 空间 稳定 适用场景
冒泡排序 O(n²) O(n²) O(n) O(1) 教学、小数据
选择排序 O(n²) O(n²) O(n²) O(1) 简单场景
插入排序 O(n²) O(n²) O(n) O(1) 小数据、近似有序
希尔排序 O(n1.25)~O(n1.5) O(n²) O(n log n) O(1) 中等规模
归并排序 O(n log n) O(n log n) O(n log n) O(n) 大数据、外排
快速排序 O(n log n) O(n²) O(n log n) O(log n) 通用排序
堆排序 O(n log n) O(n log n) O(n log n) O(1) 空间受限
计数排序 O(n+k) O(n+k) O(n+k) O(k) 整数、范围小
桶排序 O(n+k) O(n²) O(n) O(n+k) 均匀分布
基数排序 O(d×n) O(d×n) O(d×n) O(n+k) 整数、固定位数

什么是稳定性?

稳定排序:相等元素的相对顺序保持不变

示例

Text Only
原始: [(3, A), (1, B), (3, C), (2, D)]

稳定排序后: [(1, B), (2, D), (3, A), (3, C)]
                          ↑      ↑
                         A在C前(保持原顺序)

不稳定排序后: [(1, B), (2, D), (3, C), (3, A)]
                          ↑      ↑
                         C在A前(顺序改变)


初级排序算法

1️⃣ 冒泡排序(Bubble Sort)

算法思想

像气泡一样,每次将最大的元素"冒"到末尾。

Python实现

Python
def bubble_sort(arr):
    """
    冒泡排序
    时间:O(n²)
    空间:O(1)
    稳定:✅
    """
    n = len(arr)

    for i in range(n):
        # 优化:标记本轮是否有交换
        swapped = False

        for j in range(n - 1 - i):
            # 相邻元素比较
            if arr[j] > arr[j + 1]:
                arr[j], arr[j + 1] = arr[j + 1], arr[j]
                swapped = True

        # 如果没有交换,说明已经有序
        if not swapped:
            break

    return arr

# 测试
arr = [64, 34, 25, 12, 22, 11, 90]
print("排序前:", arr)
print("排序后:", bubble_sort(arr.copy()))

算法图解

Text Only
初始: [64, 34, 25, 12, 22, 11, 90]

第1轮:
[64, 34, 25, 12, 22, 11, 90]
  ↓比较  ↓
[34, 64, 25, 12, 22, 11, 90]
       ↓比较  ↓
[34, 25, 64, 12, 22, 11, 90]
            ↓比较  ↓
[34, 25, 12, 64, 22, 11, 90]
                 ↓比较  ↓
[34, 25, 12, 22, 64, 11, 90]
                      ↓比较  ↓
[34, 25, 12, 22, 11, 64, 90]
                           ↓比较  ↓
[34, 25, 12, 22, 11, 64, 90]
                           ✓ 90已到位

第2轮:
[34, 25, 12, 22, 11, 64, 90]
  ↓比较  ↓
[25, 34, 12, 22, 11, 64, 90]
       ↓比较  ↓
[25, 12, 34, 22, 11, 64, 90]
            ↓比较  ↓
[25, 12, 22, 34, 11, 64, 90]
                 ↓比较  ↓
[25, 12, 22, 11, 34, 64, 90]
                      ↓比较  ↓
[25, 12, 22, 11, 34, 64, 90]
                      ✓ 64已到位

...持续n-1轮

最终: [11, 12, 22, 25, 34, 64, 90]

复杂度分析

  • 最好情况:O(n) - 已经有序,只需一轮遍历
  • 最坏情况:O(n²) - 逆序
  • 平均情况:O(n²)

2️⃣ 选择排序(Selection Sort)

算法思想

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

Python实现

Python
def selection_sort(arr):
    """
    选择排序
    时间:O(n²)
    空间:O(1)
    稳定:❌
    """
    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

# 测试
arr = [64, 25, 12, 22, 11]
print("排序前:", arr)
print("排序后:", selection_sort(arr.copy()))

算法图解

Text Only
初始: [64, 25, 12, 22, 11]
      已排序部分为空

第1轮: 找最小值11
[64, 25, 12, 22, 11]
 ↓    ↓    ↓    ↓    ↓
比较所有元素,11最小
交换64和11
[11, 25, 12, 22, 64]
     已排序

第2轮: 找最小值12
[11, 25, 12, 22, 64]
      ↑    ↑    ↑
    未排序部分找最小
交换25和12
[11, 12, 25, 22, 64]
          已排序

第3轮: 找最小值22
[11, 12, 25, 22, 64]
           ↑     ↑
        交换25和22
[11, 12, 22, 25, 64]
               已排序

第4轮: 找最小值25
[11, 12, 22, 25, 64]
            25已经是最小

最终: [11, 12, 22, 25, 64]

3️⃣ 插入排序(Insertion Sort)

算法思想

像整理扑克牌一样,将每个元素插入到已排序部分的正确位置。

Python实现

Python
def insertion_sort(arr):
    """
    插入排序
    时间:O(n²)
    空间:O(1)
    稳定:✅

    适合:小数据、近似有序的数据
    """
    n = len(arr)

    for i in range(1, n):
        # 当前要插入的元素
        key = arr[i]
        j = i - 1

        # 将大于key的元素向后移
        while j >= 0 and arr[j] > key:
            arr[j + 1] = arr[j]
            j -= 1

        # 插入到正确位置
        arr[j + 1] = key

    return arr

# 测试
arr = [12, 11, 13, 5, 6]
print("排序前:", arr)
print("排序后:", insertion_sort(arr.copy()))

算法图解

Text Only
初始: [12, 11, 13, 5, 6]
      已排序

第1轮: 插入11
[12, 11, 13, 5, 6]
  ↓    ↓
比较: 11 < 12
后移: [12, 12, 13, 5, 6]
插入: [11, 12, 13, 5, 6]
           已排序

第2轮: 插入13
[11, 12, 13, 5, 6]
比较: 13 > 12,无需移动
[11, 12, 13, 5, 6]
               已排序

第3轮: 插入5
[11, 12, 13, 5, 6]
  ↓    ↓    ↓  ↓
比较并后移: 5 < 13, 5 < 12, 5 < 11
[11, 11, 12, 13, 6]
[5, 11, 12, 13, 6]
插入: [5, 11, 12, 13, 6]
                   已排序

第4轮: 插入6
[5, 11, 12, 13, 6]
  ↓   ↓   ↓   ↓  ↓
比较并后移: 6 < 13, 6 < 12, 6 < 11
[5, 6, 11, 12, 13]
                   已排序

最终: [5, 6, 11, 12, 13]

优化:二分插入排序

Python
def binary_insertion_sort(arr):
    """
    二分插入排序
    优化:用二分查找找到插入位置
    时间:O(n²)(虽然查找是O(log n),但移动还是O(n))
    """
    for i in range(1, len(arr)):
        key = arr[i]

        # 二分查找插入位置
        left, right = 0, i
        while left < right:
            mid = (left + right) // 2
            if arr[mid] < key:
                left = mid + 1
            else:
                right = mid

        # 移动元素
        for j in range(i, left, -1):
            arr[j] = arr[j - 1]

        # 插入
        arr[left] = key

    return arr

4️⃣ 希尔排序(Shell Sort)

算法思想

插入排序的改进版,通过比较相距一定间隔的元素来工作。

Python实现

Python
def shell_sort(arr):
    """
    希尔排序
    时间:O(n^1.25)~O(n^1.5) 平均(取决于间隔序列)
    空间:O(1)
    稳定:❌

    间隔序列:n/2, n/4, n/8, ..., 1
    """
    n = len(arr)
    gap = n // 2

    while gap > 0:
        # 对每个间隔序列进行插入排序
        for i in range(gap, n):
            temp = arr[i]
            j = i

            # 插入排序(间隔为gap)
            while j >= gap and arr[j - gap] > temp:
                arr[j] = arr[j - gap]
                j -= gap

            arr[j] = temp

        gap //= 2

    return arr

# 测试
arr = [12, 34, 54, 2, 3]
print("排序前:", arr)
print("排序后:", shell_sort(arr.copy()))

算法图解

Text Only
初始: [12, 34, 54, 2, 3], n=5
gap = 5//2 = 2

第1轮: gap=2
间隔为2的元素分组:
[12, __, 54, __, 3]  → 索引0, 2, 4
[__ 34, __, 2, __]   → 索引1, 3

组1排序: [12, 54, 3] → [3, 12, 54]
组2排序: [34, 2] → [2, 34]

合并: [3, 2, 12, 34, 54]
gap = 2//2 = 1

第2轮: gap=1(普通插入排序)
[3, 2, 12, 34, 54]
[2, 3, 12, 34, 54]

gap = 1//2 = 0,结束

最终: [2, 3, 12, 34, 54]

间隔序列优化

Python
def shell_sort_optimized(arr):
    """
    优化的Shell排序(Sedgewick间隔序列)
    """
    n = len(arr)
    gap = 1

    # 生成初始间隔
    while gap < n // 3:
        gap = gap * 3 + 1  # 1, 4, 13, 40, 121, ...

    while gap > 0:
        for i in range(gap, n):
            temp = arr[i]
            j = i
            while j >= gap and arr[j - gap] > temp:
                arr[j] = arr[j - gap]
                j -= gap
            arr[j] = temp
        gap //= 3

    return arr

高级排序算法

5️⃣ 归并排序(Merge Sort)

算法思想

分治策略: 1. 分:将数组从中间分成两部分 2. 治:递归排序两部分 3. 合:合并两个有序数组

Python实现

Python
def merge_sort(arr):
    """
    归并排序
    时间:O(n log n) 所有情况
    空间:O(n)
    稳定:✅

    适合:大数据、外部排序
    """
    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):
    """合并两个有序数组"""
    result = []
    i = j = 0

    # 比较并合并
    while i < len(left) and j < len(right):
        if left[i] <= right[j]:  # 保持稳定
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1

    # 添加剩余元素
    result.extend(left[i:])
    result.extend(right[j:])

    return result

# 测试
arr = [38, 27, 43, 3, 9, 82, 10]
print("排序前:", arr)
print("排序后:", merge_sort(arr))

算法图解

Text Only
初始: [38, 27, 43, 3, 9, 82, 10]

分解过程(递归):
[38, 27, 43, 3, 9, 82, 10]
[38, 27, 43]     [3, 9, 82, 10]
     ↓                  ↓
[38]  [27, 43]      [3, 9]  [82, 10]
        ↓              ↓        ↓
     [27] [43]       [3] [9]  [82] [10]

合并过程(递归返回):
[27] + [43] = [27, 43]
[38] + [27, 43] = [27, 38, 43]

[3] + [9] = [3, 9]
[82] + [10] = [10, 82]
[3, 9] + [10, 82] = [3, 9, 10, 82]

[27, 38, 43] + [3, 9, 10, 82] = [3, 9, 10, 27, 38, 43, 82]

最终: [3, 9, 10, 27, 38, 43, 82]

原地归并排序

Python
def merge_sort_inplace(arr):
    """原地归并排序(节省空间)"""
    if len(arr) <= 1:
        return arr

    n = len(arr)
    temp = [0] * n

    def merge_inplace(left, mid, right):
        """原地合并arr[left..mid]和arr[mid+1..right]"""
        # 复制到临时数组
        for i in range(left, right + 1):
            temp[i] = arr[i]

        i, j, k = left, mid + 1, left

        while i <= mid and j <= right:
            if temp[i] <= temp[j]:
                arr[k] = temp[i]
                i += 1
            else:
                arr[k] = temp[j]
                j += 1
            k += 1

        while i <= mid:
            arr[k] = temp[i]
            i += 1
            k += 1

    def sort(left, right):
        if left < right:
            mid = (left + right) // 2
            sort(left, mid)
            sort(mid + 1, right)
            merge_inplace(left, mid, right)

    sort(0, n - 1)
    return arr

6️⃣ 快速排序(Quick Sort)

算法思想

分治策略: 1. 选择一个基准值(pivot) 2. 将数组分为小于pivot和大于等于pivot两部分 3. 递归排序两部分

Python实现(多种方案)

Python
def quick_sort_simple(arr):
    """
    快速排序 - 简洁版(易理解,但使用额外空间)
    时间:O(n log n) 平均,O(n²) 最坏
    空间:O(n)
    稳定:❌
    """
    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_simple(left) + middle + quick_sort_simple(right)

def quick_sort_inplace(arr, low=0, high=None):
    """
    快速排序 - 原地版(面试推荐)
    时间:O(n log n) 平均,O(n²) 最坏
    空间:O(log n) - 递归栈
    """
    if high is None:
        high = len(arr) - 1

    if low < high:
        pivot_idx = partition(arr, low, high)
        quick_sort_inplace(arr, low, pivot_idx - 1)
        quick_sort_inplace(arr, pivot_idx + 1, high)

    return arr

def partition(arr, low, high):
    """Lomuto分区方案"""
    pivot = arr[high]
    i = low - 1

    for j in range(low, high):
        if arr[j] < pivot:
            i += 1
            arr[i], arr[j] = arr[j], arr[i]

    arr[i + 1], arr[high] = arr[high], arr[i + 1]
    return i + 1

def quick_sort_optimized(arr, low=0, high=None):
    """
    优化的快速排序
    优化点:
    1. 随机选择pivot(避免最坏情况)
    2. 三数取中法
    3. 小数组使用插入排序
    """
    if high is None:
        high = len(arr) - 1

    # 小数组优化:使用插入排序
    if high - low < 10:
        insertion_sort_range(arr, low, high)
        return arr

    # 三数取中法选择pivot
    mid = (low + high) // 2
    if arr[low] > arr[mid]:
        arr[low], arr[mid] = arr[mid], arr[low]
    if arr[low] > arr[high]:
        arr[low], arr[high] = arr[high], arr[low]
    if arr[mid] > arr[high]:
        arr[mid], arr[high] = arr[high], arr[mid]

    # 将中值放到high-1位置
    arr[mid], arr[high - 1] = arr[high - 1], arr[mid]

    # 分区(使用三数取中后的pivot)
    pivot_idx = partition_optimized(arr, low, high - 1, arr[high - 1])
    quick_sort_optimized(arr, low, pivot_idx - 1)
    quick_sort_optimized(arr, pivot_idx + 1, high)

    return arr

def partition_optimized(arr, low, high, pivot):
    """优化版分区"""
    i = low
    j = high

    while True:
        while arr[i] < pivot:
            i += 1
        while arr[j] > pivot:
            j -= 1
        if i >= j:
            return i
        arr[i], arr[j] = arr[j], arr[i]
        i += 1
        j -= 1

def insertion_sort_range(arr, low, high):
    """对指定范围进行插入排序"""
    for i in range(low + 1, high + 1):
        key = arr[i]
        j = i - 1
        while j >= low and arr[j] > key:
            arr[j + 1] = arr[j]
            j -= 1
        arr[j + 1] = key

# 测试
arr = [10, 7, 8, 9, 1, 5]
print("排序前:", arr)
print("排序后:", quick_sort_optimized(arr.copy()))

算法图解

Text Only
初始: [10, 7, 8, 9, 1, 5]
选择pivot = 5 (最后一个元素)

分区过程:
[10, 7, 8, 9, 1, 5]
  ↓   ↓   ↓   ↓   ↓  pivot
i=-1

j=0: 10 > 5, 不交换
j=1: 7 > 5, 不交换
j=2: 8 > 5, 不交换
j=3: 9 > 5, 不交换
j=4: 1 < 5, i=0, 交换arr[0]和arr[4]
[1, 7, 8, 9, 10, 5]
     ↑ i          ↑ j

j=5: 到达pivot,交换arr[i+1]和pivot
[1, 5, 8, 9, 10, 7]
    ↑ pivot

结果: 左=[1], 右=[8, 9, 10, 7]

递归排序左边[1]: 已排序 ✓
递归排序右边[8, 9, 10, 7]:
选择pivot=7
...
最终: [1, 5, 7, 8, 9, 10]

7️⃣ 堆排序(Heap Sort)

算法思想

利用二叉堆(完全二叉树)的性质: - 大顶堆:父节点 >= 子节点 - 小顶堆:父节点 <= 子节点

Python实现

Python
def heap_sort(arr):
    """
    堆排序
    时间:O(n log n) 所有情况
    空间:O(1)
    稳定:❌

    适合:空间受限的场景
    """
    n = len(arr)

    # 1. 建立大顶堆
    for i in range(n // 2 - 1, -1, -1):
        heapify(arr, n, i)

    # 2. 逐个提取堆顶元素(最大值)
    for i in range(n - 1, 0, -1):
        arr[0], arr[i] = arr[i], arr[0]  # 将最大值移到末尾
        heapify(arr, i, 0)  # 重新堆化

    return arr

def heapify(arr, n, i):
    """
    维护大顶堆性质
    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)

# 测试
arr = [12, 11, 13, 5, 6, 7]
print("排序前:", arr)
print("排序后:", heap_sort(arr.copy()))

算法图解

Text Only
初始数组: [12, 11, 13, 5, 6, 7]

步骤1: 建立大顶堆

数组表示(完全二叉树):
         12(0)
        /    \
     11(1)  13(2)
     /  \    /
   5(3)6(4)7(5)

堆化(从最后一个非叶子节点开始):
i=2: 节点13,子节点7,13最大,无需调整
i=1: 节点11,子节点5和6,11最大,无需调整
i=0: 节点12,子节点11和13,13最大
     交换12和13

         13(0)
        /    \
     11(1)  12(2)
     /  \    /
   5(3)6(4)7(5)

堆化完成: [13, 11, 12, 5, 6, 7]

步骤2: 逐个提取最大值

第1次:
交换13和7: [7, 11, 12, 5, 6, 13]
堆化前5个元素
         7
        /  \
      11    12
     / \
    5   6

交换7和12(12最大):
         12
        /  \
      11    7
     / \
    5   6

结果: [12, 11, 7, 5, 6, 13]

第2次:
交换12和6: [6, 11, 7, 5, 12, 13]
堆化前4个元素
         6
        /  \
      11    7
     /
    5

交换6和11(11最大):
         11
        /  \
       6    7
      /
     5

结果: [11, 6, 7, 5, 12, 13]

...持续进行

最终: [5, 6, 7, 11, 12, 13]

特殊排序算法

8️⃣ 计数排序(Counting Sort)

算法思想

统计每个元素出现的次数,然后按顺序输出。

Python实现

Python
def counting_sort(arr):
    """
    计数排序
    时间:O(n + k),k是数据范围
    空间:O(k)
    稳定:✅

    适合:整数、范围小
    """
    if not arr:
        return arr

    # 1. 找出最大值和最小值
    max_val = max(arr)
    min_val = min(arr)
    range_of_elements = max_val - min_val + 1

    # 2. 创建计数数组
    count = [0] * range_of_elements

    # 3. 统计每个元素的出现次数
    for num in arr:
        count[num - min_val] += 1

    # 4. 重构排序后的数组
    result = []
    for i in range(range_of_elements):
        result.extend([i + min_val] * count[i])

    return result

# 测试
arr = [4, 2, 2, 8, 3, 3, 1]
print("排序前:", arr)
print("排序后:", counting_sort(arr))
# 输出: [1, 2, 2, 3, 3, 4, 8]

算法图解

Text Only
初始: [4, 2, 2, 8, 3, 3, 1]
范围: 1-8

步骤1: 统计频率
值:  1  2  3  4  5  6  7  8
次数:1  2  2  1  0  0  0  1

步骤2: 累积计数(可选,用于稳定排序)
值:  1  2  3  4  5  6  7  8
累积:1  3  5  6  6  6  6  7

步骤3: 输出
1出现1次 → [1]
2出现2次 → [1, 2, 2]
3出现2次 → [1, 2, 2, 3, 3]
4出现1次 → [1, 2, 2, 3, 3, 4]
...
8出现1次 → [1, 2, 2, 3, 3, 4, 8]

最终: [1, 2, 2, 3, 3, 4, 8]

9️⃣ 桶排序(Bucket Sort)

算法思想

将元素分到有限数量的桶中,每个桶单独排序,最后合并。

Python实现

Python
def bucket_sort(arr, bucket_size=5):
    """
    桶排序
    时间:O(n + k) 平均,O(n²) 最坏
    空间:O(n + k)
    稳定:✅

    适合:均匀分布的数据
    """
    if not arr:
        return arr

    # 1. 确定最小值和最大值
    min_val, max_val = min(arr), max(arr)

    # 2. 确定桶的数量
    bucket_count = (max_val - min_val) // bucket_size + 1
    buckets = [[] for _ in range(bucket_count)]

    # 3. 将元素分配到桶中
    for num in arr:
        buckets[(num - min_val) // bucket_size].append(num)

    # 4. 对每个桶进行排序
    for bucket in buckets:
        bucket.sort()  # 使用内置排序

    # 5. 合并所有桶
    result = []
    for bucket in buckets:
        result.extend(bucket)

    return result

# 测试
arr = [0.42, 0.32, 0.33, 0.52, 0.37, 0.47, 0.51]
print("排序前:", arr)
print("排序后:", bucket_sort(arr))

🔟 基数排序(Radix Sort)

算法思想

按照位数从低位到高位进行排序。

Python实现

Python
def radix_sort(arr):
    """
    基数排序
    时间:O(d × n),d是最大位数
    空间:O(n + k)
    稳定:✅

    适合:整数、固定位数
    """
    if not arr:
        return arr

    # 1. 找出最大值,确定位数
    max_val = max(arr)

    # 2. 对每一位进行计数排序
    exp = 1  # 当前位数(个位、十位、百位...)
    while max_val // 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  # 0-9共10个数字

    # 统计当前位数的频率
    for num in arr:
        index = (num // exp) % 10
        count[index] += 1

    # 累积计数
    for i in range(1, 10):
        count[i] += count[i - 1]

    # 从后向前构建输出数组(保持稳定)
    for i in range(n - 1, -1, -1):
        index = (arr[i] // exp) % 10
        output[count[index] - 1] = arr[i]
        count[index] -= 1

    # 复制回原数组
    for i in range(n):
        arr[i] = output[i]

# 测试
arr = [170, 45, 75, 90, 802, 24, 2, 66]
print("排序前:", arr)
print("排序后:", radix_sort(arr.copy()))
# 输出: [2, 24, 45, 66, 75, 90, 170, 802]

算法图解

Text Only
初始: [170, 45, 75, 90, 802, 24, 2, 66]

第1轮: 个位数排序
170(0), 90(0), 802(2), 2(2), 24(4), 45(5), 75(5), 66(6)
→ [170, 90, 802, 2, 24, 45, 75, 66]

第2轮: 十位数排序
170(7), 802(0), 2(0), 24(2), 45(4), 75(7), 66(6), 90(9)
→ [802, 2, 24, 45, 66, 170, 75, 90]

第3轮: 百位数排序
802(8), 170(1), 75(0), 90(0), 66(0), 45(0), 24(0), 2(0)
→ [2, 24, 45, 66, 75, 90, 170, 802]

最终: [2, 24, 45, 66, 75, 90, 170, 802]

排序算法选择

决策树

Text Only
需要排序
数据规模?
    ├── 小于10 → 插入排序
    ├── 10-100 → 希尔排序或快速排序
    └── 大于100 → 快速排序或归并排序
数据特征?
    ├── 近似有序 → 插入排序或Timsort
    ├── 随机分布 → 快速排序
    ├── 大量重复 → 三路快速排序
    └── 整数且范围小 → 计数排序
是否稳定?
    ├── 是 → 归并排序、插入排序、计数排序
    └── 否 → 快速排序、堆排序、选择排序
内存限制?
    ├── 严格 → 堆排序(O(1)空间)
    └── 宽松 → 归并排序、快速排序
最终选择

实际应用建议

场景 推荐算法 原因
通用排序 快速排序 平均性能最好
大数据 归并排序 稳定O(n log n)
小数据 插入排序 简单高效
内存受限 堆排序 O(1)空间
整数小范围 计数排序 O(n)时间
外部排序 归并排序 适合文件
在线排序 插入排序 边来边排
并行排序 归并排序 易并行化

LeetCode题目

基础题

  1. 合并两个有序数组

    Python
    def merge(nums1, m, nums2, n):
        """
        LeetCode 88
        合并两个有序数组到nums1
        """
        # 从后向前合并
        p1, p2, p = m - 1, n - 1, m + n - 1
    
        while p1 >= 0 and p2 >= 0:
            if nums1[p1] > nums2[p2]:
                nums1[p] = nums1[p1]
                p1 -= 1
            else:
                nums1[p] = nums2[p2]
                p2 -= 1
            p -= 1
    
        # 复制剩余元素
        nums1[:p2 + 1] = nums2[:p2 + 1]  # 切片操作:[start:end:step]提取子序列
    

  2. 颜色分类

    Python
    def sort_colors(nums):
        """
        LeetCode 75
        荷兰国旗问题
        """
        low, mid, high = 0, 0, len(nums) - 1
    
        while mid <= high:
            if nums[mid] == 0:
                nums[low], nums[mid] = nums[mid], nums[low]
                low += 1
                mid += 1
            elif nums[mid] == 1:
                mid += 1
            else:  # nums[mid] == 2
                nums[mid], nums[high] = nums[high], nums[mid]
                high -= 1
    

  3. 最大间距

    Python
    def maximum_gap(nums):
        """
        LeetCode 164
        要求O(n)时间
        """
        if len(nums) < 2:
            return 0
    
        # 使用基数排序
        nums = radix_sort(nums)
    
        # 计算最大间距
        max_gap = 0
        for i in range(1, len(nums)):
            max_gap = max(max_gap, nums[i] - nums[i - 1])
    
        return max_gap
    

中等题

  1. 排序链表

    Python
    def sort_list(head):
        """
        LeetCode 148
        链表排序,要求O(n log n)
        """
        if not head or not head.next:
            return head
    
        # 找中点
        slow = fast = head
        while fast.next and fast.next.next:
            slow = slow.next
            fast = fast.next.next
    
        # 分割
        mid = slow.next
        slow.next = None
    
        # 递归排序
        left = sort_list(head)
        right = sort_list(mid)
    
        # 合并
        return merge_two_lists(left, right)
    

  2. 最小K个数

    Python
    def get_least_numbers(arr, k):
        """
        剑指Offer 40
        返回最小的k个数
        """
        if k == 0:
            return []
    
        # 使用堆排序
        import heapq
        return heapq.nsmallest(k, arr)
    

困难题

  1. 数组中的第K个最大元素
    Python
    def find_kth_largest(nums, k):
        """
        LeetCode 215
        """
        # 方法1: 排序后取第k个
        # return sorted(nums, reverse=True)[k - 1]
    
        # 方法2: 快速选择(期望O(n))
        def quick_select(left, right, k):
            pivot_idx = partition(left, right)
            if pivot_idx == k:
                return nums[pivot_idx]
            elif pivot_idx < k:
                return quick_select(pivot_idx + 1, right, k)
            else:
                return quick_select(left, pivot_idx - 1, k)
    
        def partition(left, right):
            pivot = nums[right]
            i = left
            for j in range(left, right):
                if nums[j] <= pivot:
                    nums[i], nums[j] = nums[j], nums[i]
                    i += 1
            nums[i], nums[right] = nums[right], nums[i]
            return i
    
        return quick_select(0, len(nums) - 1, len(nums) - k)
    

📝 总结

关键要点

排序算法分类: - 初级:冒泡、选择、插入 - 高级:归并、快速、堆 - 特殊:计数、桶、基数

核心思想: - 冒泡:相邻交换 - 选择:每次选最小 - 插入:边插入边排序 - 归并:分治合并 - 快速:分治分区 - 堆:利用堆性质

选择策略: - 通用:快速排序 - 稳定:归并排序 - 空间受限:堆排序 - 整数小范围:计数排序

下一步

继续学习: - 搜索算法 - 二分搜索、BFS、DFS