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

数据结构:排序算法详解(插入与选择排序)

介绍数据结构中的排序算法,涵盖插入排序(直接插入排序、希尔排序)和选择排序(直接选择排序、堆排序)。详细阐述了各算法的基本思想、实现代码及时间复杂度分析。直接插入排序适合小规模或接近有序数据,时间复杂度 O(N^2);希尔排序通过增量分组优化效率;直接选择排序简单但效率低;堆排序利用堆结构实现高效排序。内容包含 C++ 代码示例及关键步骤解析。

接口猎人发布于 2026/3/29更新于 2026/9/564 浏览
数据结构:排序算法详解(插入与选择排序)

插入排序过程示意图

一、排序

1.1 概念

所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。

1.2 常见的排序算法

常见排序算法分类

本文将重点讲解插入排序和选择排序。

二、插入排序

基本思想:直接插入排序是一种简单的插入排序法,其基本思想是:把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列。

实际应用中玩扑克牌时,就用了插入排序的思想。

2.1 直接插入排序

当插入第 i (i>=1) 个元素时,前面的 array[0], array[1], …, array[i-1] 已经排好序。此时用 array[i] 的排序码与 array[i-1], array[i-2], … 的排序码顺序进行比较,找到插入位置即将 array[i] 插入,原来位置上的元素顺序后移。

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

直接插入排序的特性总结:

  1. 元素集合越接近有序,直接插入排序算法的时间效率越高。
  2. 时间复杂度:O(N^2)
  3. 空间复杂度:O(1)

2.2 希尔排序

希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数(通常是 gap = n/3+1),把待排序文件所有记录分成各组,所有的距离相等的记录分在同一组内,并对每一组内的记录进行排序。然后 gap=gap/3+1 得到下一个整数,再将数组分成各组,进行插入排序,当 gap=1 时,就相当于直接插入排序。

它是在直接插入排序算法的基础上进行改进而来的,综合来说它的效率肯定是要高于直接插入排序算法的。

希尔排序分组示意

一组一组来使用直接插入,组的间隙慢慢变小,最后一层就是直接插入排序。这种方式相比于直接插入排序,外层的 ++ 循环变成了 gap 的递减,从 O(N) 到 O(logN)。

代码实现如下:

void ShellSort(int* a, int n) {
    int gap = n;
    while (gap > 1) {
        gap = gap / 3 + 1;
        for (int i = 0; i < n - gap; i++) {
            int end = i;
            int tmp = a[end + gap];
            while (end >= 0) {
                if (a[end] > tmp) {
                    a[end + gap] = a[end];
                    end -= gap;
                } else {
                    break;
                }
            }
            a[end + gap] = tmp;
        }
    }
}
希尔排序的时间复杂度

外层循环的时间复杂度为 O(log n)。内层循环次数随 gap 变化。希尔排序在最初和最后的排序的次数都为 n,即前一阶段排序次数是逐渐上升的状态,当到达某一顶点时,排序次数逐渐下降至 n。

因此,希尔排序的时间复杂度为:O(n log n) ~ O(n^2),最好的情况为 O(n^1.3),最坏的情况为 O(n^2)。

三、选择排序

选择排序的基本思想:每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。

3.1 直接选择排序

  1. 在元素集合 array[i]–array[n-1] 中选择关键码最大 (小) 的数据元素。
  2. 若它不是这组元素中的最后一个 (第一个) 元素,则将它与这组元素中的最后一个(第一个)元素交换。
  3. 在剩余的 array[i]–array[n-2](array[i+1]–array[n-1])集合中,重复上述步骤,直到集合剩余 1 个元素。

通俗来讲,先遍历一遍,找一个最小的数据,放第一个,然后遍历第二个到最后一个数据,找最小放在第二个。这样一直遍历,放置,数据就排好了。

void SelectSort(int* a, int n) {
    int begin = 0, end = n - 1;
    while (begin < end) {
        int mini = begin, maxi = begin;
        for (int i = begin; i < end; i++) {
            if (a[i] < a[mini]) {
                mini = i;
            }
            if (a[i] > a[maxi]) {
                maxi = i;
            }
        }
        if (maxi == begin) {
            maxi = mini;
        }
        swap(a[mini], a[begin]);
        swap(a[maxi], a[end]);
        begin++;
        end--;
    }
}

直接选择排序的特性总结:

  1. 思考非常好理解,但是效率不是很好。实际中很少使用。
  2. 时间复杂度:O(N^2)
  3. 空间复杂度:O(1)

3.2 堆排序

堆排序主要基于二叉堆结构,需要深刻理解向下调整算法和向上调整算法。

void AdjustDown(int* a, int parent, int n) {
    int child = parent * 2 + 1;
    while (child < n) {
        if (child + 1 < n && a[child] > a[child + 1]) {
            child++;
        }
        if (a[child] < a[parent]) {
            swap(a[child], a[parent]);
            parent = child;
            child = parent * 2 + 1;
        } else {
            break;
        }
    }
}

void HeapSort(int* a, int n) {
    for (int i = (n - 1 - 1) / 2; i >= 0; i--) {
        AdjustDown(a, i, n);
    }
    int end = n - 1;
    while (end > 0) {
        swap(a[0], a[end]);
        AdjustDown(a, 0, end);
        end--;
    }
}

以上代码供复习使用。

目录

  1. 一、排序
  2. 1.1 概念
  3. 1.2 常见的排序算法
  4. 二、插入排序
  5. 2.1 直接插入排序
  6. 2.2 希尔排序
  7. 希尔排序的时间复杂度
  8. 三、选择排序
  9. 3.1 直接选择排序
  10. 3.2 堆排序

更多推荐文章

查看全部
  • LeetCode 141 题:环形链表检测算法
  • 大模型时代人形机器人感知:视觉 - 语言模型应用
  • [AI提效-18]-豆包AI绘图提示词全攻略(新手可直接套用)
  • Python 驱动浏览器自动化:Playwright 与 AI 结合实战
  • AI 绘画精讲与 AIGC 游戏美术设计
  • JDK 下载与安装配置详解
  • AI 办公实战指南:7 套书籍助你精准提效与职场进阶
  • 代价驱动的 SQL 连接条件下推实践
  • SchoolCMS 智慧校园管理平台功能与部署指南
  • Socket 标准参数详解:BACKLOG、KEEPALIVE 与 TCP_NODELAY
  • 基于 AI 快速开发 MCP 服务插件并实现本地与线上部署
  • C++ 虚函数深度解析:多态、语法与底层原理
  • C++ 继承中的同名成员隐藏规则详解
  • Self-Attention 与 Multi-head Attention 核心原理及代码实现
  • VS Code 中 GitHub Copilot 安装后无法使用?关键排查步骤
  • 动态规划:买卖股票的最佳时机含手续费
  • 高精度混凝土缺陷与桥梁病害巡检数据集(YOLO 格式)
  • 本地训练专属大模型:DeepSeek-R1 微调实战指南
  • Windows 下安装 OpenClaw 并接入飞书机器人
  • FastAPI 架构深度解析:依赖注入、后台任务与 WebSocket 实战

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如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