跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C算法

数据结构基础:直接插入、希尔与选择排序详解

直接插入排序、希尔排序及选择排序是三种经典算法。直接插入排序基于扑克牌整理逻辑,稳定但效率低;希尔排序通过分组预排序优化插入效率,时间复杂度随增量序列变化;选择排序每次选取最小值交换位置,不稳定且效率固定为 O(n^2)。文章提供 C 语言实现代码,分析各算法的时间空间复杂度及优缺点,适合理解排序底层原理。

Elasticer发布于 2026/3/30更新于 2026/10/2194 浏览
数据结构基础:直接插入、希尔与选择排序详解

数据结构基础:直接插入、希尔与选择排序详解

排序算法是数据结构的基石,不仅关乎代码效率,更体现了对数据组织规律的理解。本文将深入探讨三种经典排序算法:直接插入排序、希尔排序和选择排序,通过原理剖析、复杂度分析及 C 语言实现,帮助读者建立扎实的底层认知。

直接插入排序

算法原理

想象一下打扑克牌的过程:摸到第二张牌时,我们会将其插入到手中已排好序的牌堆中合适的位置。直接插入排序正是模拟这一过程,将数组分为有序区和无序区,每次从无序区取出一个元素,插入到有序区的正确位置。

实现步骤

  1. 默认第一个元素为有序区。
  2. 从第二个元素开始,依次与前面的有序元素比较。
  3. 若当前元素小于前一个元素,则后移前一个元素,继续向前比较。
  4. 找到合适位置后插入,重复直至所有元素有序。

文章配图

文章配图

文章配图

文章配图

文章配图

复杂度分析

  • 时间复杂度:
    • 最好情况(已有序):O(n),只需比较一次。
    • 最坏情况(逆序):O(n^2),每个元素都需要移动。
  • 空间复杂度:O(1),原地排序,仅需常数级辅助变量。
  • 稳定性:稳定排序。

代码实现

为了便于理解,我们先实现单次插入逻辑,再扩展至整体排序。

// tmp 是待插入元素,end 是当前比较元素的下标
int tmp = arr[i];
int end = i - 1;
while (end >= 0) {
    if (arr[end] > tmp) {
        // 元素后移
        arr[end + 1] = arr[end];
        end--;
    } else {
        break;
    }
}
// 插入
arr[end + 1] = tmp;

完整函数实现如下:

#include <assert.h>

void InsertSort(int* arr, int size) {
    assert(arr);
    for (int i = 1; i < size; i++) {
        int tmp = arr[i];
        int end = i - 1;
        while (end >= 0) {
            if (arr[end] > tmp) {
                arr[end + 1] = arr[end];
                end--;
            } else {
                break;
            }
        }
        arr[end + 1] = tmp;
    }
}

注意:传参时直接使用数组名即可,无需取地址符 &。建议动手画图模拟执行过程,有助于理解指针移动细节。

优缺点总结

  • 优点:稳定,代码简洁,对小规模或基本有序的数据效率较高。
  • 缺点:大规模数据下 O(n^2) 的时间开销较大,效率较低。

希尔排序

算法原理

希尔排序(Shell Sort)是对直接插入排序的优化。核心思想是通过设定增量序列,将数组分组进行预排序,使数据在整体上逐步趋向有序,最后再进行直接插入排序。这大大减少了元素的交换次数。

实现步骤

  1. 选择一个初始间隔 interval(通常为 size / 2)。
  2. 按间隔将数组分成若干子序列,分别进行直接插入排序。
  3. 缩小间隔(如 interval /= 2),重复上述过程。
  4. 当间隔为 1 时,进行最后一次直接插入排序,完成整体有序。

文章配图

复杂度分析

  • 时间复杂度:取决于增量序列的选择。最坏情况 O(n^2),最佳情况接近 O(n log n)。
  • 空间复杂度:O(1)。
  • 稳定性:不稳定。

代码实现

我们同样采用分步实现的思路,先处理单组,再扩展到多组。

// interval 是间隔
int interval = size / 2;
while (interval >= 1) {
    for (int j = 0; j < interval; j++) {
        for (int i = j; i < size - interval; i += interval) {
            int tmp = arr[i + interval];
            int end = i;
            while (end >= 0) {
                if (arr[end] > tmp) {
                    arr[end + interval] = arr[end];
                    end -= interval;
                } else {
                    break;
                }
            }
            arr[end + interval] = tmp;
        }
    }
    interval /= 2;
}

优化说明:

  • 动态调整间隔大小,避免固定间隔导致的低效。
  • 当间隔为 1 时,直接衔接插入排序逻辑,无需额外调用接口。

优缺点总结

  • 优点:相比直接插入排序,显著提升了中等规模数据的排序效率。
  • 缺点:时间复杂度仍受增量序列影响,不如归并或快排稳定高效。

选择排序

算法原理

选择排序的基本思想是:每一轮从未排序部分选出最小值,与未排序部分的第一个元素交换位置。每轮确定一个元素的最终位置。

实现步骤

  1. 遍历无序区间,记录最小值的索引。
  2. 将最小值与无序区间的起始位置交换。
  3. 更新无序区间起始位置,重复直至结束。

文章配图

复杂度分析

  • 时间复杂度:无论数据是否有序,均需遍历查找,始终为 O(n^2)。
  • 空间复杂度:O(1),原地排序。
  • 稳定性:不稳定,交换操作可能破坏相同元素的相对顺序。

代码实现

void SelectSort(int* arr, int size) {
    assert(arr);
    for (int i = 0; i < size - 1; i++) {
        int minIdx = i;
        for (int j = i + 1; j < size; j++) {
            if (arr[j] < arr[minIdx]) {
                minIdx = j;
            }
        }
        if (minIdx != i) {
            int tmp = arr[i];
            arr[i] = arr[minIdx];
            arr[minIdx] = tmp;
        }
    }
}

优缺点总结

  • 优点:实现简单,交换次数少(最多 n-1 次)。
  • 缺点:效率低,不稳定,不适合对性能有要求的大规模场景。

以上三种算法构成了排序学习的基础。理解它们的原理与局限,有助于在实际开发中根据数据特征选择合适的策略。后续我们将继续探讨更高效的排序算法。

目录

  1. 数据结构基础:直接插入、希尔与选择排序详解
  2. 直接插入排序
  3. 算法原理
  4. 实现步骤
  5. 复杂度分析
  6. 代码实现
  7. 优缺点总结
  8. 希尔排序
  9. 算法原理
  10. 实现步骤
  11. 复杂度分析
  12. 代码实现
  13. 优缺点总结
  14. 选择排序
  15. 算法原理
  16. 实现步骤
  17. 复杂度分析
  18. 代码实现
  19. 优缺点总结

更多推荐文章

查看全部
  • RocketMQ 顺序消息详解:全局与分区实现及最佳实践
  • 网页滚动定位导航特效实现
  • 双指针算法实战:从三角形计数到四数之和
  • 基于 Cosmos-Reason1-7B 的机器人抓取物理推理分析
  • Kubernetes 完全指南:从集群架构到应用模型
  • 中国人工智能大模型技术白皮书核心内容梳理与学习指南
  • CRMEB v5.6.1 单商户应用部署指南:环境配置与进程守护
  • 前端精确数字运算:使用 BigNumber.js 解决 JavaScript 精度问题
  • Python 爬虫逆向兼职实战指南
  • 基于 rocketmq-client-python 构建高效 RocketMQ 消息系统
  • Flutter 与 React Native 跨平台移动应用开发技术对比指南
  • Java 微服务架构设计模式:构建云原生分布式系统
  • C/C++ 核心:函数指针与回调函数实战详解
  • AI 大模型核心知识点梳理与原理分析
  • Spring AOP 核心概念与实战入门
  • 世界模型发展脉络综述:理解世界与预测未来
  • Flutter Web 刷新后页面回退功能失效的解决方案
  • OpenCLaw 对接本地 Ollama 与 Qwen WebUI 无响应排查
  • Scratch 与 Python 编程语言核心差异对比
  • 国内 AI 大模型现状与实用工具推荐

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online