【排序算法】八大经典排序算法详解

排序算法是计算机科学中最基础且应用最广泛的核心算法之一。本文将深入解析八种经典排序算法的原理、实现方式及适用场景,帮助读者全面掌握排序算法的核心知识。


一、直接选择排序(Selection Sort)

算法思想

通过不断选择剩余元素中的最小值,将其与当前未排序部分的起始位置交换,逐步构建有序序列。

算法步骤

  1. 从未排序序列中找到最小元素
  2. 将该元素与未排序序列的起始位置元素交换
  3. 将已排序序列的边界向右移动一位
  4. 重复上述过程直到整个序列有序
python 复制代码
def selection_sort(arr):
    for i in range(len(arr)):
        min_idx = i
        for j in range(i+1, len(arr)):
            if arr[j] < arr[min_idx]:
                min_idx = j
        arr[i], arr[min_idx] = arr[min_idx], arr[i]

特性分析

  • 时间复杂度:O(n²)(始终进行n(n-1)/2次比较)
  • 空间复杂度:O(1)
  • 稳定性:不稳定(交换可能破坏原有顺序)
  • 适用场景:教学演示、数据量极小时使用

二、堆排序(Heap Sort)

算法思想

利用堆这种数据结构的特性,通过构建大顶堆实现排序,将最大值依次交换到数组末尾。

关键步骤

  1. 建堆:从最后一个非叶子节点开始调整,构建大顶堆
  2. 排序阶段
    • 交换堆顶与当前末尾元素
    • 堆大小减1
    • 调整新堆顶使其满足堆性质
python 复制代码
def heapify(arr, n, i):
    largest = i
    l = 2 * i + 1
    r = 2 * i + 2
    if l < n and arr[l] > arr[largest]:
        largest = l
    if r < n and arr[r] > arr[largest]:
        largest = r
    if largest != i:
        arr[i], arr[largest] = arr[largest], arr[i]
        heapify(arr, n, largest)

def heap_sort(arr):
    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)

特性分析

  • 时间复杂度:O(n log n)
  • 空间复杂度:O(1)
  • 稳定性:不稳定
  • 优势:适合处理海量数据,不需要递归栈
  • 应用场景:实时数据流处理、优先级队列实现

三、直接插入排序(Insertion Sort)

算法思想

将待排序元素逐个插入到已排序序列的适当位置,类似整理扑克牌的过程。

算法步骤

  1. 从第一个元素开始视为已排序序列
  2. 取出下一个元素,在已排序序列中从后向前扫描
  3. 找到第一个小于等于当前元素的节点,插入其后
  4. 重复步骤2-3直到所有元素处理完成
python 复制代码
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

特性分析

  • 最佳时间复杂度:O(n)(已排序情况)
  • 平均时间复杂度:O(n²)
  • 空间复杂度:O(1)
  • 稳定性:稳定
  • 适用场景:小规模数据(n ≤ 1000)、基本有序数据

四、希尔排序(Shell Sort)

算法思想

通过将原始列表分割成多个子序列进行插入排序,随着增量逐渐减小,最终实现整体有序。

核心概念

  • 增量序列:确定子序列划分方式的间隔序列(常用Hibbard增量)
  • 分组插入:对每个增量间隔形成的子序列进行插入排序
python 复制代码
def shell_sort(arr):
    n = len(arr)
    gap = n // 2
    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 //= 2

特性分析

  • 时间复杂度:O(n^1.3) ~ O(n²)(取决于增量序列)
  • 空间复杂度:O(1)
  • 稳定性:不稳定
  • 优势:中等规模数据高效排序
  • 历史意义:第一个突破O(n²)时间复杂度的排序算法

五、冒泡排序(Bubble Sort)

算法思想

通过相邻元素的比较和交换,使较大元素逐渐"浮"到数列顶端。

优化策略

  1. 提前终止:设置交换标志位检测是否已有序
  2. 边界优化:记录最后一次交换位置,减少无效比较
python 复制代码
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

特性分析

  • 最佳时间复杂度:O(n)(已排序情况)
  • 平均时间复杂度:O(n²)
  • 空间复杂度:O(1)
  • 稳定性:稳定
  • 应用价值:算法教学、简单场景应用

六、快速排序(Quick Sort)

算法思想

采用分治策略,通过选定基准元素将数组划分为两个子数组,递归排序。

关键步骤

  1. 基准选择:通常选第一个/中间/随机元素
  2. 分区操作:将小于基准的元素放在左侧,大于的放在右侧
  3. 递归处理:对左右子数组重复上述过程
python 复制代码
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)

特性分析

  • 平均时间复杂度:O(n log n)
  • 最坏时间复杂度:O(n²)(已排序数组+选择首元素为基准)
  • 空间复杂度:O(log n)(递归栈深度)
  • 稳定性:不稳定
  • 优化方向:三数取中法、尾递归优化、小数组切换插入排序

七、归并排序(Merge Sort)

算法思想

典型的分治算法,将数组递归分割到最小单位后合并有序子数组。

核心操作

  1. 分割阶段:递归地将数组二分至单个元素
  2. 合并阶段:将两个有序数组合并为新的有序数组
python 复制代码
def merge_sort(arr):
    if len(arr) > 1:
        mid = len(arr)//2
        L = arr[:mid]
        R = arr[mid:]
        merge_sort(L)
        merge_sort(R)
        
        i = j = k = 0
        while i < len(L) and j < len(R):
            if L[i] < R[j]:
                arr[k] = L[i]
                i += 1
            else:
                arr[k] = R[j]
                j += 1
            k += 1
        
        while i < len(L):
            arr[k] = L[i]
            i += 1
            k += 1
        
        while j < len(R):
            arr[k] = R[j]
            j += 1
            k += 1

特性分析

  • 时间复杂度:O(n log n)
  • 空间复杂度:O(n)
  • 稳定性:稳定
  • 优势:适合链表结构、外部排序
  • 应用场景:大数据排序(内存不足时使用外部归并)

八、基数排序(Radix Sort)

算法思想

按位分割的非比较排序,从最低位(LSD)或最高位(MSD)开始进行多轮排序。

执行步骤

  1. 初始化10个桶(0-9)
  2. 从最低位到最高位依次进行:
    • 分配:按当前位数字将元素放入对应桶
    • 收集:按桶顺序将元素放回原数组
  3. 重复直到处理完所有位数
python 复制代码
def radix_sort(arr):
    max_num = max(arr)
    exp = 1
    while max_num // exp > 0:
        buckets = [[] for _ in range(10)]
        for num in arr:
            buckets[(num // exp) % 10].append(num)
        arr = [num for bucket in buckets for num in bucket]
        exp *= 10
    return arr

特性分析

  • 时间复杂度:O(nk)(k为最大位数)
  • 空间复杂度:O(n+k)
  • 稳定性:稳定(依赖桶排序的稳定性)
  • 限制条件:仅适用于整数排序
  • 优化技巧:结合计数排序、动态确定位数

九、排序算法对比

算法优缺点对比

算法 最佳场景 优势 局限性 稳定性
直接选择排序 教学演示 实现简单 效率低下 不稳定
堆排序 内存敏感的大数据 无递归栈溢出风险 缓存局部性差 不稳定
插入排序 小规模有序数据 自适应性能好 大规模数据效率骤降 稳定
希尔排序 中等规模随机数据 突破O(n²)屏障 增量序列选择复杂 不稳定
冒泡排序 检测数据有序性 实现简单 效率最低 稳定
快速排序 通用排序场景 平均性能最优 最坏情况性能差 不稳定
归并排序 大数据外部排序 稳定且时间复杂度优 空间复杂度高 稳定
基数排序 固定范围整数排序 线性时间复杂度 数据类型限制 稳定

算法复杂度对比

总结

理解这些基础排序算法不仅是掌握数据结构的关键,更是优化实际工程问题的基础。建议读者通过可视化工具(如 Visualgo)观察算法的执行过程,并尝试自己实现不同版本的排序算法来加深理解。

相关推荐
keep intensify几秒前
【数据结构】- 栈
c语言·数据结构·算法·
小白学大数据5 分钟前
基于Python的携程国际机票价格抓取与分析
开发语言·爬虫·python
小技与小术23 分钟前
代码随想录算法训练营day12(二叉树)
数据结构·python·算法
焱童鞋28 分钟前
贪吃蛇游戏demo
人工智能·python·pygame
Chrome深度玩家29 分钟前
微博安卓版话题热度推荐算法与内容真实性分析
算法·机器学习·推荐算法
Demons_kirit37 分钟前
LeetCode LCP40 心算挑战题解
java·数据结构·算法·leetcode·职场和发展
星空40 分钟前
从 Python 基础到 Django 实战 —— 数据类型驱动的 Web 开发之旅
python·django
每次的天空1 小时前
Android面试总结之GC算法篇
android·算法·面试
从零开始学习人工智能2 小时前
深度解析 MindTorch:无缝迁移 PyTorch 到 MindSpore 的高效工具
人工智能·pytorch·python
EanoJiang2 小时前
树与二叉树
算法