前言
欢迎来到软考中级软件设计师备考系列博客!在软件设计师综合知识中,数据结构 是必考章节,分值稳定在10分左右(基础知识),是整个考试的核心重点之一。本章内容涵盖线性结构、数组与矩阵、树、图、查找和排序六大模块,知识点多且杂,但考点相对固定,规律性强。
数据结构不仅是选择题的高频考点,也是应用题中算法题的基础。掌握好数据结构,对于理解操作系统、数据库系统等后续章节也有重要帮助。本系列博客将严格按照最新考试大纲编写,结合历年真题,对每个知识点进行详细讲解,并配套典型例题和深度解析,帮助大家快速掌握考点,高效备考。
一、线性结构
1.1 线性表
1.1.1 线性表的定义
线性表是n个元素的有限序列,通常记为 (a₁, a₂, ..., aₙ)。其特点如下:
-
存在唯一的一个称为"第一个"的元素(表头)
-
存在唯一的一个称为"最后一个"的元素(表尾)
-
除了表头外,表中的每一个元素均只有唯一的直接前驱
-
除了表尾外,表中的每一个元素均只有唯一的直接后继
1.1.2 线性表的存储结构
1. 顺序存储
线性表的顺序存储是用一组地址连续的存储单元依次存储线性表中的数据元素,使得逻辑关系相邻的两个元素在物理位置上也相邻。

优点:可以随机存取表中的元素,存储密度高。
缺点:插入和删除操作需要移动大量的元素;大片连续空间分配不方便。
第i个元素aᵢ的存储位置:
LOC(aᵢ) = LOC(a₁) + (i-1) × L
其中,LOC(a₁)为表中第一个元素的存储位置,L为每个元素所占空间的大小。
2. 链式存储
线性表的链式存储用节点来存储数据元素,节点空间可以是连续的,也可以是不连续的。存储数据元素的同时必须存储元素之间的逻辑关系(指针域)。

优点:插入和删除操作不需要移动元素,只需修改指针;离散小空间分配方便。
缺点:不能随机访问,只能顺序存取;存储密度低。
单链表插入操作(在p所指结点后插入s所指结点):

cpp
s->next = p->next;
p->next = s;
单链表删除操作(删除p所指结点的后继结点):

cpp
q = p->next;
p->next = p->next->next;
free(q);
考点总结:平均时间复杂度对比
| 操作 | 顺序表 | 单链表 |
|---|---|---|
| 取值(随机访问) | O(1) | O(n) |
| 查找 | O(n) | O(n) |
| 插入 | O(n) | O(n) |
| 删除 | O(n) | O(n) |
注意:链表插入删除本身是O(1),但查找插入位置需要O(n)。
3. 其他链表结构
-
双向链表:每个结点包含两个指针(前驱和后继),可双向遍历
-
循环链表:表尾结点指针指向第一个结点,可从任意结点开始遍历
-
静态链表:借助数组描述链式存储,用数组下标表示指针

典型例题
例题1:以下关于线性表采用链式存储的叙述中,正确的是( )。
A. 逻辑上相邻的元素物理位置也必须相邻
B. 插入和删除操作需要移动元素
C. 可以随机访问表中的任意元素
D. 每个结点包含数据域和指针域
答案:D
解析:链式存储中,逻辑相邻的元素物理位置不一定相邻,插入删除只需修改指针不需要移动元素,只能顺序访问不能随机访问。每个结点由数据域和指针域组成。
1.2 栈和队列
1.2.1 栈

栈是只允许在一端 进行插入或删除操作的线性表。栈的修改按**先进后出(FILO)**的原则进行。
-
栈顶(Top):允许插入和删除的一端
-
栈底(Bottom):固定的一端
-
空栈:不含数据元素的栈
栈的基本操作:
-
入栈 Push:将元素加入栈顶
-
出栈 Pop:删除栈顶元素
-
读栈顶元素 Top:返回栈顶元素值,不修改指针
-
判栈空 Empty
栈空/栈满判断条件
- 初始化 top = -1 时,栈空条件:top == -1 ,栈满条件:top + 1 == MaxSize
栈的典型应用:表达式求值、括号匹配、递归调用、函数调用。
1.2.2 队列
1.队列的定义
队列 是一种先进先出(First In First Out,FIFO)的线性表,它只允许在表的一端插入元素,而在表的另一端删除元素。在队列中,允许插入元素的一端称为队尾(Rear) ,允许删除元素的一端称为队头(Front)。
2.队列的存储结构
队列的顺序存储。队列的顺序存储结构又称为顺序队列,它也是利用一组地址连续的存储单元存放队列中的元素。由于队列中元素的插入和删除限定在表的两端进行,因此设置队头指针和队尾指针,分别指出当前的队头和队尾。
下面设顺序队列Q的容量为6,其队头指针为front,队尾指针为rear,头、尾指针和队列中元素之间的关系如图3-6。

循环队列
为解决"假溢出"问题,将顺序队列假想成环状结构,称为循环队列。

设循环队列Q的容量为MAXSIZE,初始时队列为空,且Q.rcar和Q.font都等于0,如图下图所示。

- **元素入队时,**修改队尾指针Qrear=(Qrear+1)%MAXSIZE,如图(b)
- **元素出队时,**修改队头指针Q.fromt=(Q.fron+1)%MAXSIZE,如图(c)
根据队列操作的定义,当出队操作导致队列变为空时,则有Qrear==Q.front,如图(d)
若入队操作导致队列满,则Q.rear==Q.front,如图(e)
在队列空和队列满的情况下,循环队列的队头、队尾指针指向的位置是相同的,此时仅仅根据Q.rear和Q.front之间的关系无法断定队列的状态。为了区别队空和队满的情况,可采用以下两种处理方式:其一是设置一个标志,以区别头、尾指针的值相同时队列是空还是满;其二是牺牲一个存储单元,约定以"队列的尾指针所指位置的下一个位置是队头指针时"表示队列满,如图(f)所示,而头、尾指针的值相同时表示队列为空。
队空与队满的区分
循环队列中,队空和队满时都有 Q.rear == Q.front,无法区分。常用解决方法:
-
牺牲一个存储单元:队尾指针的下一个位置是队头时表示队满
-
设置标志位区分空和满
队列长度公式:(rear - front + MAXSIZE) % MAXSIZE
双端队列

双端队列允许在两端进行入队操作,但仅允许在一端进行出队操作(输出受限),或允许在两端出队但仅一端入队(输入受限)。
典型例题
例题1:某队列允许在其两端进行入队操作,但仅允许在一端进行出队操作。若元素a、b、c、d依次全部入队列,之后进行出队操作,则不能得到的出队序列是( )。
A. dbac B. cabd C. acdb D. bacd
答案:C
解析:这是输出受限的双端队列(两端入、一端出)。a、b、c、d依次入队后,出队端只能从固定的一端出。选项C中a先出后c再出,中间跳过了b,不可能实现。
例题3:设循环队列的存储空间为Q(1:m),初始状态为空。现经过一系列正常的入队与退队操作后,front=m-1,rear=m,则该循环队列中的元素个数为( )。A. 1 B. m-1 C. m D. 2
答案:A
解析:循环队列元素个数 = (rear - front + m) % m = (m - (m-1) + m) % m = 1。
1.3 串
1.3.1 串的基本概念
-
空串:长度为零的串
-
空格串:由一个或多个空格组成的串(空格也是字符)
-
子串:由串中任意长度的连续字符构成的序列
-
主串:含有子串的串
1.3.2 串的模式匹配
1. 朴素模式匹配(暴力匹配)
从主串第一个字符起与模式串第一个字符比较,相等则继续,否则主串回溯到下一个位置重新比较。
-
最好时间复杂度:O(n+m)
-
最坏时间复杂度:O(n×m)
2. KMP算法
改进的模式匹配算法,利用已匹配的信息避免主串指针回溯。通过构建next数组实现。
next数组求法:第i个字符的next值 = 前1~i-1个字符组成的串中最长相等前后缀的长度 + 1
特殊情况:next[1] = 0,next[2] = 1
时间复杂度:O(n+m)
设主串为"abacbcabababbcbc",模式串为"abababb",且模式串的next函数值如下表所示,则KMP算法的匹配过程如图3-10所示。其中,i是主串字符的下标,j是模式串字符的下标。

第一趟匹配从SO与PO开始。由于SO==PO、S1---P1、S2=P2,所以接下来比较S3与P3,由于S3与P3不相等,所以第一趟结束,要进行第二趟匹配,令j=nex3(即j-1)。第二趟从S3与P1开始比较,仍不相等,因此第二趟结束,要进行第三趟匹配,所以令j=next/(即j-0)。第三趟从S3与PO开始比较,如图3-10(a)所示。由于S3与PO不相等,所以令j=nextO(即j=-1),此时满足条件"j==-1",显然不能令S3与P-1进行比较,说明主串中从i=3开始的子串不可能与模式串相同,因此需要将i的值递增后再继续进行匹配过程,即令i计+、j++,然后下一趟从S4与PO开始比较,如图3-10(b)所示,继续匹配过程。直到某一趟匹配成功,或者由于在主串中找不到模式串而以失败结束。(这个算法可以看看视频理解,记住方法即可,可以不理解)
典型例题
例题1:已知模式串"ababaaababaa",则next数组值为( )。
A. 012345678999 B. 012121111212 C. 011234223456 D. 012301232234
答案:C
解析:根据KMP的next数组定义,逐位计算最长相等前后缀长度加1。next1=0,next2=1,依次推导可得结果为C。
二、数组、矩阵和广义表
数组与广义表可看作是线性表的推广,其特点是数据元素仍然是一个表。这里讨论多维数组的逻辑结构和存储结构,特殊矩阵和矩阵的压缩存储,广义表的逻辑结构、存储结构和基本运算。
2.1 数组
数组是定长线性表在维数上的扩张,特点是数据元素数目固定、类型相同、下标有序。
二维数组的地址计算

设每个元素占L个单元,m行n列:
-
按行优先 :
LOC(aᵢⱼ) = LOC(a₁₁) + ((i-1)×n + (j-1)) × L -
按列优先 :
LOC(aᵢⱼ) = LOC(a₁₁) + ((j-1)×m + (i-1)) × L
注意:下标从0开始时公式相应调整,去掉-1即可。
2.2 矩阵
2.2.1 特殊矩阵
-
对称矩阵:aᵢⱼ = aⱼᵢ,可压缩存储到 n(n+1)/2 个空间
-
三角矩阵:上三角或下三角元素全为0或常数
-
三对角矩阵:非零元素集中在主对角线及其两侧
若矩阵中元素(或非0元素)的分布有一定的规律,则称之为特殊矩阵。常见的特殊矩阵有对称矩阵、三角矩阵和对角矩阵等。对于特殊矩阵,由于其非0元素的分布有一定的规律,所以可将其压缩存储在一维数组中,并建立起每个非0元素在矩阵中的位置与其在一维数组中的位置之间的对应关系。
若矩阵A中的元素特点为aᵢⱼ = aⱼᵢ(1≤i,j≤n),则称之为n阶对称矩阵。
若对称矩阵中的每一对元素仅占用一个存储单元,那么可将n²个元素压缩存储到能存放n(n+1)/2 个元素的存储空间中。不失一般性,以行为主序存储下三角(包括对角线)中的元素。假设以一维数Bn(n+1)/2 作为n阶对称矩阵A中元素的存储空间,则**BK(1≤k<n(n+1)/2)**与矩阵元素aᵢⱼ (aⱼᵢ)之间存在着一一对应的关系,如下所示。

对角矩阵是指矩阵中的非0元素都集中在以主对角线为中心的带状区域中,即除了主对角线上和直接在对角线上、下方若干条对角线上的元素外,其余的矩阵元素都为0。一个n阶的三对角矩阵如图:

若以行为主序将n阶三对角矩阵An×n的非 0 元素aij存储在一维数组Bk(1≤k≤3×n−2)中, 则元素位置之间的对应关系为k=3×(i−1)−1+j−i+1+1=2i+j−2(1≤i, j≤n) 其他特殊矩阵可做类似的推算。
2.2.2 稀疏矩阵
在一个矩阵中,若非 0 元素的个数远远少于 0 元素的个数,且非 0 元素的分布没有规律,则称之为稀疏矩阵。对于稀疏矩阵,存储非 0 元素时必须同时存储其位置(即行号和列号),所以三元组(i,j,aij)可唯一确定矩阵A中的一个元素。由此,一个稀疏矩阵可由表示非 0 元素的三元组及其行、列数唯一确定。如下图所示的是一个 6 行 7 列的稀疏矩阵,
其三元组表为((1,2,12),(1,3,9),3,1,-3),3,6,14),(4,3,24), (5,2,18),(6,1,15),(6,4,-7))。

稀疏矩阵的三元组表的顺序存储结构称为三元组顺序表,常用的三元组表的链式存储结构是十字链表。
2.3 广义表
广义表是n个元素的有限序列,元素可以是原子,也可以是子表。
-
取表头 head(L):取广义表的第一个元素
-
取表尾 tail(L):取除第一个元素外剩余元素构成的广义表
典型例题
例题1:设广义表 L = ((x, y, z), a, (u, t, w)),则从L中取出原子项y的运算是( )。
A. head(tail(tail(L))) B. tail(head(head(L)))
C. head(tail(head(L))) D. tail(tail(head(L)))
答案:C
解析:head(L) = (x, y, z),tail(head(L)) = (y, z),head(tail(head(L))) = y。
三、树
3.1 树的基本概念
树是n(n≥0)个结点的有限集合。非空树满足:
-
有且仅有一个根结点
-
其余结点可分为m个互不相交的子集,每个子集本身又是一棵树(子树)
重要术语:
-
结点的度:一个结点的子树个数
-
叶子结点:度为0的结点(终端结点)
-
树的度:树中所有结点度的最大值
-
树的高度(深度):树的最大层次数
-
森林:m棵互不相交的树的集合
树的常考性质
总结点数 = 总度数 + 1
度为m的树第i层至多有 m^(i-1) 个结点
高度为h的m叉树至多有 (m^h - 1)/(m - 1) 个结点
具有n个结点的m叉树的最小高度为 ⌈logₘ(n(m-1)+1)⌉
3.2 二叉树
3.2.1 二叉树的定义
二叉树每个结点最多有两棵子树,且子树有左右之分,次序不能颠倒。
特殊二叉树:
-
满二叉树:深度为k且有2ᵏ-1个结点的二叉树
-
完全二叉树:除最后一层外,每层结点数都达到最大;最后一层结点从左到右连续排列
3.2.2 二叉树的重要性质【考点】
-
第i层上最多有 2^(i-1) 个结点(i≥1)
-
深度为k的二叉树最多有 2ᵏ - 1 个结点
-
叶子结点数 = 度为2的结点数 + 1,即 n₀ = n₂ + 1
-
具有n个结点的完全二叉树的深度为 ⌊log₂n⌋ + 1
完全二叉树结点编号性质(按层序从1开始编号)
结点i的双亲:⌊i/2⌋
结点i的左孩子:2i(若2i≤n)
结点i的右孩子:2i+1(若2i+1≤n)
3.2.3 二叉树的存储结构
-
顺序存储:适合完全二叉树,一般二叉树会浪费空间。最坏情况(单支树):深度为k需2ᵏ-1个单元
-
链式存储 :二叉链表(数据+左右指针)。n个结点的二叉链表有 n+1个空链域
3.2.4 二叉树的遍历【高频考点】
| 遍历方式 | 遍历顺序 | 口诀 |
|---|---|---|
| 先序遍历 | 根 → 左 → 右 | 根左右 |
| 中序遍历 | 左 → 根 → 右 | 左根右 |
| 后序遍历 | 左 → 右 → 根 | 左右根 |
| 层序遍历 | 按层次从上到下、从左到右 | 队列实现 |
做题技巧:
先序 + 中序 → 可唯一确定一棵二叉树
后序 + 中序 → 可唯一确定一棵二叉树
先序 + 后序 → 不能唯一确定
先序序列第一个是根;后序序列最后一个是根;中序中根左边是左子树,右边是右子树
典型例题
例题6:若一棵二叉树有20个度为2的结点,则该二叉树的叶子结点数为( )。
A. 19 B. 20 C. 21 D. 22
答案:C
解析:根据二叉树性质 n₀ = n₂ + 1,叶子结点数 = 20 + 1 = 21。
例题7:已知某二叉树的先序遍历序列为ABDCEF,中序遍历序列为DBAECF,则其后序遍历序列为( )。
A. DBEFCA
B. DBEFCA
C. DFEBCA
D. DBFECA
答案:A
解析:先序第一个A是根。中序中A左边DB是左子树,右边ECF是右子树。递归构造二叉树,后序遍历得DBEFCA。
3.3 最优二叉树(哈夫曼树)
哈夫曼树:带权路径长度(WPL)最小的二叉树。
构造方法:每次选取权值最小的两棵树合并,新树根的权值为两树权值之和。
-
n个叶子结点的哈夫曼树共有 2n-1 个结点
-
哈夫曼树中没有度为1的结点
哈夫曼编码:左分支记为0,右分支记为1,从根到叶子的路径编码。是一种前缀编码(任一编码都不是其他编码的前缀)。
四、图
4.1 图的定义与存储
4.1.1 基本概念
-
有向图:边有方向(弧)
-
无向图:边无方向
-
完全图:n个顶点的无向完全图有 n(n-1)/2 条边;有向完全图有 n(n-1) 条弧
-
连通图(无向):任意两顶点都连通。n个顶点的连通图至少有 n-1 条边
-
强连通图(有向):任意两顶点双向都有路径
-
生成树:包含图中全部顶点的极小连通子图,有 n-1 条边
4.1.2 图的存储结构
| 存储方式 | 空间复杂度 | 适用场景 |
|---|---|---|
| 邻接矩阵 | O(n²) | 稠密图 |
| 邻接表 | O(n+e) | 稀疏图 |
| 逆邻接表 | O(n+e) | 有向图,便于求入度 |
4.2 图的遍历
4.2.1 深度优先搜索(DFS)
类似于树的先序遍历,尽可能深地搜索。使用栈或递归实现。
时间复杂度:邻接矩阵 O(n²),邻接表 O(n+e)
4.2.2 广度优先搜索(BFS)
类似于树的层序遍历,逐层扩展。使用队列实现。
时间复杂度:与DFS相同,仅存储结构不同。
4.3 拓扑排序和关键路径
4.3.1 拓扑排序
对有向无环图(DAG)的顶点排序,使得对于任意弧<vᵢ, vⱼ>,vᵢ都排在vⱼ之前。
算法步骤:
-
选一个入度为0的顶点输出
-
删除该顶点及其所有出边
-
重复直到所有顶点输出(或检测到环)
4.3.2 关键路径
AOE网(边表示活动的网)中,从源点到汇点的最长路径称为关键路径。关键路径上的活动称为关键活动。
-
最早发生时间ve:从源点正向推导,取最大值
-
最晚发生时间vl:从汇点反向推导,取最小值
-
活动最早开始时间e = 起点的ve
-
活动最晚开始时间l = 终点的vl - 活动持续时间
-
关键活动:e = l 的活动
典型例题
例题8:对于一个具有n个顶点和e条边的无向图,采用邻接表存储时,所有顶点邻接表中的结点总数为( )。
A. n
B. e
C. 2e
D. n+e
答案:C
解析:无向图每条边在两个顶点的邻接表中各出现一次,所以总边结点数为2e。
五、查找
5.1 查找的基本概念
| 类型 | 包含方法 | 操作特点 |
|---|---|---|
| 静态查找表 | 顺序查找、折半查找、分块查找 | 只做查询和检索 |
| 动态查找表 | 二叉排序树、平衡二叉树、B-树、哈希表 | 插入和删除操作 |
平均查找长度(ASL):查找过程中关键字比较次数的期望值。
5.2 静态查找表
5.2.1 顺序查找
-
适用:顺序存储或链式存储,有序无序均可
-
最多比较n次
-
平均查找长度:ASL = (n+1)/2
-
时间复杂度:O(n)
5.2.2 折半查找(二分查找)【高频考点】
-
适用条件:顺序存储 + 元素有序
-
最多比较次数:⌊log₂n⌋ + 1
-
平均查找长度:log₂(n+1) - 1
-
时间复杂度:O(log₂n)
折半查找判定树:
折半查找的过程可用二叉判定树描述。查找成功的比较次数不超过树的深度。
mid = ⌊(low + high)/2⌋(默认下取整,下取整无答案时考虑上取整)
5.2.3 分块查找
性能介于顺序查找和折半查找之间。块间有序,块内无序。先查索引表确定块,再块内顺序查找。
5.3 动态查找表
5.3.1 二叉排序树(BST)
左子树所有结点值 < 根结点值 < 右子树所有结点值。
中序遍历二叉排序树可得到递增有序序列。
5.3.2 平衡二叉树(AVL树)
左右子树高度差不超过1的二叉排序树。
平衡因子 = 左子树高度 - 右子树高度,取值 -1, 0, 1。
插入失衡时通过旋转调整:LL、RR、LR、RL四种类型。
5.3.3 B-树
多路平衡查找树。m阶B-树特点:
-
根结点至少2棵子树
-
非根结点至少 ⌈m/2⌉ 棵子树
-
所有叶子结点在同一层
5.4 哈希表
5.4.1 基本概念
通过哈希函数 H(key) 将关键字映射到存储地址。
冲突:不同关键字映射到同一哈希地址。
装填因子 α = 表中记录数 / 哈希表长度。α越小,冲突概率越低。
5.4.2 哈希函数构造方法
除留余数法 (最常用):H(key) = key % p
p取不大于表长且最接近表长的质数。
5.4.3 处理冲突的方法
1. 开放地址法
Hᵢ = (H(key) + dᵢ) % m
-
线性探测法:dᵢ = 1, 2, 3, ... → 会产生二次聚集
-
二次探测法:dᵢ = 1², -1², 2², -2², ... → 避免二次聚集
-
伪随机探测法
2. 链地址法
相同哈希地址的记录链接在同一个单链表中。
典型例题
例题9:以下关于折半查找的叙述中,不正确的是( )。
A. 是一个分治算法
B. 只能应用于有序表
C. 查找成功和不成功的平均查找长度是一样的
D. 若表长为n,时间复杂度为O(log₂n)
答案:C
解析:折半查找成功和不成功的平均查找长度不同。不成功时需要比较到叶子结点的外部结点,查找长度更大。
例题10:采用折半查找等概率查找某个包含8个元素的有序表,查找成功的平均查找长度为( )。A. 9/8
B. 1/8
C. 20/8
D. 21/8
答案:D
解析:8个元素的判定树:第1层1个(比较1次),第2层2个(比较2次),第3层4个(比较3次),第4层1个(比较4次)。ASL = (1×1 + 2×2 + 3×4 + 4×1)/8 = (1+4+12+4)/8 = 21/8。
六、排序
6.1 排序的基本概念
稳定性:若关键字相同的两个记录,排序前后相对次序不变,则排序方法是稳定的。
6.2 简单排序
6.2.1 直接插入排序
-
思想:将记录插入到已排好序的有序表中
-
时间复杂度:最好O(n),平均/最坏O(n²)
-
空间复杂度:O(1)
-
稳定排序
-
适合初始基本有序的情况
6.2.2 冒泡排序
-
思想:两两比较相邻记录,逆序则交换
-
时间复杂度:最好O(n),平均/最坏O(n²)
-
空间复杂度:O(1)
-
稳定排序
6.2.3 简单选择排序
-
思想:每趟选最小元素放到有序区末尾
-
时间复杂度:O(n²)(无论初始排列,比较次数相同)
-
空间复杂度:O(1)
-
不稳定排序
-
每趟确定一个元素的最终位置(归位)
6.3 希尔排序
-
思想:缩小增量排序,分组插入排序
-
时间复杂度:平均O(n^1.3),最坏O(n²)
-
空间复杂度:O(1)
-
不稳定排序
6.4 快速排序【高频考点】
-
思想:基于分治法,选枢轴将序列分成两部分,递归排序
-
时间复杂度:平均/最好O(nlog₂n),最坏O(n²)(基本有序时)
-
空间复杂度:O(log₂n) ~ O(n)(递归栈)
-
不稳定排序
-
每趟确定枢轴的最终位置
快速排序最坏情况:待排序序列基本有序时,退化为冒泡排序,时间复杂度O(n²)。
6.5 堆排序
-
思想:利用大根堆/小根堆,堆顶为最大/最小值
-
时间复杂度:O(nlog₂n)(最好、最坏、平均都一样)
-
空间复杂度:O(1)
-
不稳定排序
-
每趟确定一个元素的最终位置
-
建堆时间O(n),n较大时高效
6.6 归并排序
-
思想:将有序子序列两两归并
-
时间复杂度:O(nlog₂n)(最好、最坏、平均都一样)
-
空间复杂度:O(n)
-
稳定排序
6.7 基数排序
-
思想:按关键字各位分配和收集
-
时间复杂度:O(d(n+r)),d为位数,r为基数
-
稳定排序
6.8 排序算法总结
| 排序算法 | 平均时间 | 最坏时间 | 最好时间 | 空间复杂度 | 稳定性 |
|---|---|---|---|---|---|
| 直接插入排序 | O(n²) | O(n²) | O(n) | O(1) | 稳定 |
| 希尔排序 | O(n^1.3) | O(n²) | O(n) | O(1) | 不稳定 |
| 冒泡排序 | O(n²) | O(n²) | O(n) | O(1) | 稳定 |
| 简单选择排序 | O(n²) | O(n²) | O(n²) | O(1) | 不稳定 |
| 快速排序 | O(nlogn) | O(n²) | O(nlogn) | O(logn) | 不稳定 |
| 堆排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(1) | 不稳定 |
| 归并排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(n) | 稳定 |
| 基数排序 | O(d(n+r)) | O(d(n+r)) | O(d(n+r)) | O(n+r) | 稳定 |
考点速记
-
每趟归位一个元素:简单选择排序、堆排序、快速排序、冒泡排序
-
最坏情况仍是O(nlogn):堆排序、归并排序
-
稳定排序:直接插入、冒泡、归并、基数
-
不稳定排序:希尔、简单选择、快速、堆
-
n较小时:选简单排序方法;基本有序时选直接插入或冒泡
-
n较大时:快速排序平均最快;要求稳定选归并;最坏情况也要O(nlogn)选堆排序
典型例题
例题1:以下排序算法中,( )在最坏情况下的时间复杂度最高。
A. 堆排序 B. 归并排序 C. 快速排序 D. 希尔排序
答案:C
解析:快速排序在最坏情况下(基本有序)时间复杂度为O(n²),堆排序和归并排序最坏都是O(nlogn),希尔排序最坏O(n²)但通常比快速排序的最坏情况好。
例题2:对n个记录进行排序,若要求排序是稳定的,且关键字为整数,则在下列排序方法中应选( )。A. 快速排序 B. 堆排序 C. 归并排序 D. 简单选择排序
答案:C
解析:选项中只有归并排序是稳定的。快速排序、堆排序、简单选择排序都是不稳定的。
结语
数据结构是软件设计师考试的重中之重,建议大家在理解基本概念的基础上,多做历年真题,重点掌握二叉树性质、遍历、查找算法、排序算法对比等高频考点。尤其是排序算法的时间复杂度、空间复杂度和稳定性对比,几乎年年必考,务必熟记于心。
下一篇我们将继续学习操作系统相关考点,敬请期待!如果本文对你有帮助,欢迎点赞收藏支持