菜单

排序算法

相关源文件

排序算法是将元素按特定顺序(通常是升序或降序)排列的基本过程。本页面涵盖了 Hello Algo 仓库中各种排序算法的原理、实现和计算效率。有关搜索算法,请参阅 搜索算法

排序算法概述

排序是计算机科学中最常见的操作之一,并且是许多其他算法的基础。排序算法以元素集合作为输入,并将其重新排列成某种顺序,最常见的是数值顺序或字典顺序。

来源: docs/chapter_computational_complexity/time_complexity.md1096-1183

排序算法分类

排序算法可以根据各种属性进行分类

基于稳定性

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

基于内存使用

  • 原地排序:需要 O(1) 的额外空间
  • 非原地排序:需要与输入大小成比例的额外内存

基于比较

  • 基于比较的排序:通过比较元素进行排序(例如,冒泡、快速、归并)
  • 非比较排序:使用其他技术(例如,计数、基数、桶排序)

来源: docs/chapter_computational_complexity/time_complexity.md1096-1183

常见排序算法

冒泡排序

冒泡排序是一种最简单的排序算法,它重复地遍历列表,比较相邻元素,如果它们的顺序不对就交换它们。

算法步骤

  1. 比较相邻元素
  2. 如果顺序不对则交换
  3. 重复直到不需要交换

时间复杂度

  • 最坏情况:O(n²)
  • 最佳情况:O(n)(经过优化)
  • 平均情况:O(n²)

空间复杂度:O(1)

来源: docs/chapter_computational_complexity/time_complexity.md1112-1118 docs/chapter_sorting/bubble_sort.md1-5

快速排序

快速排序是一种高效的“分而治之”的排序算法,它通过选择一个“枢轴”元素并将数组围绕该枢轴进行分区来实现。

算法步骤

  1. 从数组中选择一个枢轴元素
  2. 划分数组:将小于枢轴的元素移到其左侧,大于枢轴的元素移到其右侧
  3. 递归地对子数组应用上述步骤

时间复杂度

  • 最坏情况:O(n²)(罕见,发生在枢轴选择不当的情况下)
  • 最佳情况:O(n log n)
  • 平均情况:O(n log n)

空间复杂度:O(log n)(由于递归栈)

来源: docs/chapter_sorting/quick_sort.md1-7

堆排序

堆排序利用堆数据结构的特性高效地对元素进行排序。

算法步骤

  1. 从输入数组构建最大堆
  2. 将堆顶(最大元素)与最后一个元素交换
  3. 将堆大小减 1,并对堆顶进行堆化
  4. 重复步骤 2-3,直到堆大小为 1

时间复杂度:所有情况均为 O(n log n) 空间复杂度:O(1)

来源: docs/chapter_heap/heap.md537-538

归并排序

归并排序是一种分而治之算法,它将输入数组分成两半,递归地对它们进行排序,然后合并已排序的半部分。

算法步骤

  1. 将输入数组分成两半
  2. 递归地对两个半部分进行排序
  3. 合并已排序的半部分以生成已排序的数组

时间复杂度:所有情况均为 O(n log n) 空间复杂度:O(n)

来源: docs/chapter_computational_complexity/time_complexity.md1181-1182

排序算法比较

下表总结了不同排序算法的关键特征

算法时间复杂度(最佳)时间复杂度(平均)时间复杂度(最坏)空间复杂度稳定
冒泡排序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(n log n)O(n log n)O(n²)O(log n)
归并排序O(n log n)O(n log n)O(n log n)O(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(n+k)
基数排序O(nk)O(nk)O(nk)O(n+k)
桶排序O(n+k)O(n+k)O(n²)O(n*k)

其中 n 是元素数量,k 是输入范围或数字位数。

来源: docs/chapter_computational_complexity/time_complexity.md1052-1061

时间复杂度可视化

下图显示了排序算法中常见时间复杂度的增长率

来源: docs/chapter_computational_complexity/time_complexity.md1065-1072

算法选择指南

选择排序算法时,请考虑以下因素

  • 数据量:对于小型数据集,由于开销较低,插入排序等简单算法可能表现更好
  • 内存限制:在内存有限的情况下,堆排序等原地排序算法更受青睐
  • 稳定性要求:当相等元素的相对顺序很重要时,选择稳定的算法
  • 数据分布:对于接近有序的数据,插入排序可能非常高效
  • 键范围:对于范围有限的整数,计数排序可以实现 O(n) 的时间复杂度

来源: docs/chapter_heap/heap.md537-538 docs/chapter_computational_complexity/time_complexity.md1181-1182

实际应用

排序算法是许多应用中的基本构建块

  1. 数据库系统:用于高效的查询处理和索引
  2. 搜索算法:许多搜索算法需要排序数据
  3. 优先队列:堆排序的原理用于优先队列的实现
  4. 统计分析:用于计算中位数、百分位数和其他统计量
  5. 压缩算法:一些压缩技术依赖于排序数据
  6. 计算机图形学:用于深度排序和渲染优化

排序算法的实际选择通常取决于具体的应用需求、数据特征和系统约束。

来源: docs/chapter_heap/heap.md537-538