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

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


一、直接选择排序(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)观察算法的执行过程,并尝试自己实现不同版本的排序算法来加深理解。

相关推荐
ElvInR32 分钟前
冒泡排序详解
c语言·c++·排序算法·冒泡排序
inksci1 小时前
Python web 开发 Flask HTTP 服务
python·flask
爱coding的橙子1 小时前
每日算法刷题计划day13 5.22:leetcode不定长滑动窗口最短/最小1道题+求子数组个数越长越合法2道题,用时1h
算法·leetcode·职场和发展
编程绿豆侠1 小时前
力扣HOT100之二叉树: 437. 路径总和 III
算法·leetcode·哈希算法
范纹杉想快点毕业2 小时前
Google C++ Style Guide 谷歌 C++编码风格指南,深入理解华为与谷歌的编程规范——C和C++实践指南
c语言·数据结构·c++·qt·算法
熊猫在哪2 小时前
野火鲁班猫(arrch64架构debian)从零实现用MobileFaceNet算法进行实时人脸识别(一)conda环境搭建
linux·人工智能·python·嵌入式硬件·神经网络·机器学习·边缘计算
烨然若神人~2 小时前
算法第26天 | 贪心算法、455.分发饼干、376. 摆动序列、 53. 最大子序和
算法·贪心算法
满怀10152 小时前
【Python中的Socket套接字详解】网络通信的核心基石
开发语言·网络·python·网络编程·socket
信奥洪老师2 小时前
2025年 全国青少年信息素养大赛 算法创意挑战赛C++ 小学组 初赛真题
c++·算法·青少年编程·等级考试
学习使我变快乐2 小时前
C++:关联容器set容器,multiset容器
开发语言·c++·算法