408数据结构第8章:排序①——内部排序算法原理与过程

适用:考研408数据结构

章节:第8章 排序

目标:先搞懂"每种排序到底在干什么",重点掌握408最常考的一趟结果、时间复杂度、稳定性、适用场景


一、排序这一章先抓住什么

408排序题基本绕不开四件事:

复制代码
1. 排序过程:一趟之后序列变成什么
2. 性质判断:稳定 / 不稳定,原地 / 非原地
3. 复杂度:最好、平均、最坏
4. 场景选择:基本有序、数据量大、外存、链表等该选谁

先不要急着背代码,先把每个算法的"动作特征"记住。


二、插入排序

1. 直接插入排序

核心思想:

复制代码
左边始终保持有序,
每次从右边拿一个元素,
插入到左边正确位置。

例如:

复制代码
初始:5 2 4 6 1 3

第一趟把2插入到5前:

复制代码
2 5 4 6 1 3

第二趟把4插入到2、5之间:

复制代码
2 4 5 6 1 3

408秒杀特征

看到:

复制代码
前面一段已经有序
下一个元素向前移动插入

就是直接插入排序。

性质

复制代码
最好:O(n)       ------ 原序列基本有序
平均:O(n^2)
最坏:O(n^2)     ------ 原序列逆序
空间:O(1)
稳定:是

特别适合

复制代码
数据量小
序列基本有序

2. 折半插入排序

和直接插入排序本质一样,只是:

复制代码
用折半查找寻找插入位置

所以它减少的是:

复制代码
比较次数

但是元素仍然要整体移动,因此:

复制代码
移动次数仍可能是O(n^2)

结论

复制代码
比较次数下降
整体时间复杂度仍是O(n^2)
稳定

408常见陷阱:

折半插入排序用了二分查找,所以时间复杂度是O(n log n)。

错误。

原因:

复制代码
找位置快了
移动元素仍然慢

3. 希尔排序

核心思想:

复制代码
先让相距较远的元素进行插入排序,
逐渐缩小间隔gap,
最后gap=1时再做一次插入排序。

可以理解成:

复制代码
把序列先"粗略排顺"
再慢慢变成真正有序

性质

复制代码
空间:O(1)
稳定:否
时间复杂度:依赖增量序列

408里不要强行背一个唯一复杂度。

重点记:

复制代码
希尔排序不稳定
属于插入排序的改进
增量最后必须为1

三、交换排序

1. 冒泡排序

核心思想:

复制代码
相邻元素两两比较,
逆序就交换,
一趟把一个最大元素"冒"到最后。

升序时第一趟:

复制代码
最大的元素到最右边

第二趟:

复制代码
次大的元素到倒数第二个位置

性质

带"本趟是否发生交换"的标志位时:

复制代码
最好:O(n)
平均:O(n^2)
最坏:O(n^2)
空间:O(1)
稳定:是

408识别点

如果题目说:

复制代码
一趟后最大元素一定归位

优先想到冒泡排序。


2. 快速排序

快速排序是408高频重点。

核心思想:

复制代码
选一个枢轴pivot,
通过一趟划分,
让pivot左边都不大于它,
右边都不小于它,
此时pivot最终位置确定。

然后:

复制代码
递归处理左区间和右区间

一趟划分最重要的结论

复制代码
一趟划分结束后:
pivot的位置已经最终确定

但:

复制代码
pivot左边内部不一定有序
pivot右边内部也不一定有序

性质

复制代码
最好:O(n log n)
平均:O(n log n)
最坏:O(n^2)

递归栈:
平均 O(log n)
最坏 O(n)

稳定:否

什么时候最坏

如果固定选第一个元素作为pivot,而序列已经:

复制代码
基本有序
或
完全逆序

可能每次都只能划出:

复制代码
0个元素 + n-1个元素

于是退化成:

复制代码
O(n^2)

什么时候最好

每次pivot都基本把序列平均分成两半:

复制代码
T(n) ≈ 2T(n/2) + O(n)

所以:

复制代码
O(n log n)

408秒杀口诀

复制代码
快排一趟:
枢轴归位
左右不一定有序

四、选择排序

1. 简单选择排序

核心思想:

复制代码
每一趟从未排序区间中找最小值,
放到当前最前面。

例如:

复制代码
5 2 4 1 3

第一趟找最小1:

复制代码
1 2 4 5 3

第二趟再从后面找最小2。

性质

无论原序列是否有序:

复制代码
比较次数基本不变

总比较次数:

复制代码
n(n-1)/2

所以:

复制代码
最好:O(n^2)
平均:O(n^2)
最坏:O(n^2)
空间:O(1)
稳定:否

特点

它的交换次数很少:

复制代码
最多n-1次

408会考:

哪种O(n^2)排序比较次数不受初始序列影响?

优先想到:

复制代码
简单选择排序

2. 堆排序

堆排序也是408重点。

升序排列一般建立:

复制代码
大根堆

原因:

复制代码
堆顶最大
每次把最大值交换到最后

然后缩小堆范围,再调整。

两个核心动作

复制代码
1. 建堆
2. 删除堆顶 + 向下调整

复杂度

复制代码
建堆:O(n)
每次调整:O(log n)
共做约n次

总时间:O(n log n)
空间:O(1)
稳定:否

而且:

复制代码
最好、平均、最坏都为O(n log n)

顺序存储下标

若从1开始编号:

复制代码
结点i的左孩子:2i
结点i的右孩子:2i+1
父结点:floor(i/2)

408高频

复制代码
升序 -> 大根堆
降序 -> 小根堆

不要记反。


五、归并排序

二路归并排序

核心思想:

复制代码
先把两个有序子序列合成一个更大的有序序列

不断两两合并:

复制代码
1个元素
-> 2个元素有序段
-> 4个元素有序段
-> 8个元素有序段
...

一次二路归并

例如:

复制代码
左:2 5 8
右:1 4 9

用两个指针比较:

复制代码
1 2 4 5 8 9

性质

复制代码
最好:O(n log n)
平均:O(n log n)
最坏:O(n log n)

额外空间:O(n)
稳定:是

适合

复制代码
链表
外部排序
需要稳定排序

408高频点

若有n个元素,二路归并趟数:

复制代码
ceil(log2 n)

六、基数排序

基数排序不靠关键字之间直接比较。

例如三位十进制数:

复制代码
329
457
657
839
436
720
355

LSD法:

复制代码
先按个位分配收集
再按十位
最后按百位

每一位都使用桶。

时间复杂度

设:

复制代码
n:元素个数
d:关键字位数
r:每一位可能的取值数

则:

复制代码
O(d(n+r))

空间:

复制代码
O(n+r)

稳定性:

复制代码
通常稳定

408重点

基数排序:

复制代码
不是比较排序

所以它不受比较排序:

复制代码
Ω(n log n)

这个下界限制。


七、九种算法先建立"动作记忆"

复制代码
直接插入:拿一个,向前插

折半插入:二分找位置,再移动

希尔:分组插入,gap逐渐减小

冒泡:相邻交换,大的往后冒

快速:pivot划左右,pivot归位

简单选择:每趟找最小放前面

堆排序:堆顶最大,交换到末尾

归并:两个有序段合成一个

基数:按个位、十位、百位分桶

八、408常见"看一趟结果猜算法"

如果一趟后:

复制代码
最大元素一定在最后

可能:

复制代码
冒泡

如果一趟后:

复制代码
某个pivot左边都更小
右边都更大
pivot最终位置确定

就是:

复制代码
快速排序

如果一趟后:

复制代码
第一个位置放上全局最小元素

可能:

复制代码
简单选择排序

如果前面一段始终保持有序

可能:

复制代码
直接插入排序

如果序列呈现"每隔gap一组分别有序"

可能:

复制代码
希尔排序

九、这一篇需要你掌握到什么程度

至少做到:

复制代码
看到算法名
-> 知道一趟在干什么

看到中间序列
-> 大概能判断是哪种排序

看到复杂度/稳定性选项
-> 能快速排除明显错误

下一篇专门整理:

复制代码
所有排序算法复杂度
稳定性
空间复杂度
初始序列影响
场景选择
外部排序
408选择题秒杀表
相关推荐
坚持编程的菜鸟10 小时前
模拟实现memmove
c语言·算法·模拟实现memmove
wabs66611 小时前
关于图论【最短路径之Dijkstra算法(堆优化版)|卡码网47.参加科学大会的思考】
数据结构·算法·图论·优先级队列·邻接表·小顶堆·卡码网
坚持编程的菜鸟11 小时前
编写判断大小端程序
c语言·算法·判断大小端
papaofdoudou11 小时前
判断排列逆序奇偶性的乘积判别法(范德蒙德符号法)
人工智能·算法
linux-hzh12 小时前
百日算法修炼 · Day 03
java·算法
问商十三载12 小时前
RAG 检索效果差怎么排查?2026 五层诊断法完整指南
开发语言·人工智能·windows·python·算法
嵌入式老牛13 小时前
三相电气量采集模块设计(三)非同步采样时的精度提升
算法·精度·计量
今天AI了吗14 小时前
精细化落地教程:TimechoAI调参标准+数据清洗规范+误差归因+阈值适配全维度指南
大数据·人工智能·算法
zephyr0515 小时前
从递归到迭代:二叉树非递归前中后序遍历详解
算法
Dr.kangder15 小时前
嵌入式总线设备解析——TTE总线应用与实践
开发语言·网络·算法·嵌入式·多任务·同步机制