目录
1.1 考纲及知识框架(2022考纲)
- 掌握数据结构的基本概念、基本原理和基本方法。
- 掌握数据的逻辑结构、存储结构及基本操作的实现,能够对算法进行基本的时间复杂度与空间复杂度的分析。
- 能够运用数据结构基本原理和方法进行问题的分析与求解,具备采用 C 或 C++语言设计与实现算法的能力。
- 思维导图
- 主要看逻辑结构、存储结构(物理结构)、时间复杂度
1.2 数据结构基本概念
1.2.1 基本概念
数据结构是相互之间存在一种或多种特定关系的数据元素的集合,数据元素相互之间的关系称为结构。
数据结构包括三方面的内容:逻辑结构、存储结构和数据的运算。
算法的设计取决于逻辑结构,算法的实现依赖于所采用的存储结构。
1.2.2 数据结构三要素(*重点,三者缺一不可)
1.数据的逻辑结构
逻辑结构是指数据元素之间的逻辑关系,与数据的存储无关,是独立于计算机的。
数据的逻辑结构分为线性结构和非线性结构,线性表是典型的线性结构;集合、树和图是典型的非线性结构。数据的逻辑结构分类如下所示:
① 线性结构:结构中的数据元素之间只存在一对一的关系
② 集合:结构中的数据元素之间除“同属一个集合外”,别无其他关系
③ 树形结构:结构中元素之间存在一对多的关系
④ 图状结构或网状结构:结构中的数据元素之间存在多对对的关系
2.数据的存储结构
存储结构是指数据结构在计算机中的表示(又称映象),也称物理结构。它包括数据元素的表示和关系的表示。
数据的存储结构是用计算机语言实现的逻辑结构,依赖于计算机语言。主要有顺序存储、链式存储、索引存储和散列存储。
① 顺序存储:逻辑上相邻的元素存储在物理上也相邻的存储单元中。
② 链式存储:不要求逻辑相邻,物理也相邻,借助指示元素存储地址的指针来表示元素之间的逻辑关系。
③ 索引存储:除存储元素外,还建立索引表。索引表中的每项称为索引项,索引项的一般形式是(关键字,地址)。
④ 散列存储:根据元素的关键字直接计算出该元素的存储地址,又称哈希(Hash)存储。
四种存储结构优缺点对比:
顺序存储
优点:可以实现随机存取,每个元素占用最少的存储空间
缺点:只能使用相邻的一整块存储单元,因此可能产生较多的外部碎片
链式存储
优点:不会出现外部碎片,能充分利用所有存储单元
缺点:每个元素因素存储指针而占用额外的空间,且只能顺序存取
索引存储
优点:索引速度快
缺点:索引表额外占用空间,增加和删除时也需要修改索引表
散列存储
优点:增、删、查等操作都很快
缺点:若散列函数不好,可能会出现存储单元冲突,解决冲突会增加时空开销
注:这四种存储方式在操作系统、计算机组成原理中都有体现,后续内容中也包含相关内容,如散列表等
3.数据的运算
施加在数据上的运算包括运算的定义和实现。运算的定义是针对逻辑结构的,指出功能;运算的实现是针对存储结构的,指出运算的具体操作步骤。
1.2.3 其他(*看不懂建议看完一部分数据结构再回头看)
① 抽象数据类型(ADT)描述了数据的逻辑结构和抽象运算,通常用(数据对象、数据关系、数据操作集)表示,可表示一个完整的数据结构。
② 顺序表、哈希表、单链表和栈描述逻辑结构。
③ 有序表是存储结构。
④ 数据的逻辑结构采用抽象的表达方式,独立于存储结构,同一种逻辑结构可以有多种存储结构;但存储结构是逻辑结构在计算机上的映射,不能独立于逻辑结构而存在。
⑤ 相同的逻辑结构,同一种运算在不同的存储结构下实现时,效率不同。如线性表可以用顺序存储和链式存储实现,其中对于插入和删除元素,顺序存储因为要移动元素,平均时间复杂度是O(n),而链表中则都是O(1)。
⑥ 两种不同的数据结构,逻辑结构和物理结构也可能相同,如二叉树和二叉排序树,他们的操作效率也可能不同,如查找,二叉树的时间效率是O(n),二叉排序树是O()。
1.3 算法和算法评价
1.3.1 算法的基本概念
算法是对特定问题求解步骤的一种描述,它是指令的有限序列,每条指令表示一个或多个操作。此外, 一个算法具有下列5个特征:
① 有穷性:一个算法必须在有穷步后结束,且每一步时间也必须有穷;
② 确定性:每条指令必须有确切的含义,且相同输入得到相同输出;
③ 可行性:算法中的操作可以通过已实现的基本运算执行有限次来实现;
④ 输入:一个算法可以有零个或多个输入;
⑤ 输出:一个算法可以有一个或多个输出,输入输出之间存在特定关系。
好的算法具有下列特征:
① 正确性:能正确解决问题;
② 可读性:良好的可读性;
③ 健壮性:能对非法输入做出反应或者适当处理,不会出现奇奇怪怪的结果;
④ 效率和低存储要求:即算法所需的时间和空间,这与问题规模有关。
1.3.2 算法效率的衡量(*重点)
1. 时间复杂度
一个语句的频度指该语句在算法中被重复执行的次数,算法中所有语句的频度之和记为T(n),它是算法问题规模n的函数,时间复杂度主要分析T(n)的数量级。
算法中基本运算的频度与T(n)的数量级相同,因此采用分析算法中基本运算的频度f(n)来分析算法的时间复杂度。因此,算法的时间复杂度记为
最坏时间复杂度指最坏情况下,算法的时间复杂度;平均时间复杂度指所有可能输入实例等概率出现的情况下,算法的期望运行时间;最好时间复杂度指最好情况下,算法的时间复杂度。一般总考虑最坏时间复杂度,保证算法时间不会比它长。
分析时间复杂度的两条规则:
① 加法规则:O(f(n)) + O(g(n)) = O(max(f(n), g(n)))
② 乘法规则:O(f(n)) * O(g(n)) = O(f(n) * g(n))
常用时间复杂度排序
O(1) < O(
) < O(n) < O(n
) < O(
) < O(
) < O(
) < O(n!) < O(
)
2. 空间复杂度
算法的空间复杂度S(n)定义为算法耗费的存储空间,它是问题规模n的函数。记为:
算法的空间复杂度包括本身的指令、常数、变量和输入数据以及计算可能产生的数据占用的额外空间。
算法原地工作指算法所需的辅助空间为常量,即O(1)。
3. 相关练习
考研喜欢给一个代码段,然后分析时间复杂度,或对算法设计题自己设计的算法求时间空间复杂度。
(1)求时间复杂度
void fun(int n){
int i = 1;
while(i <= n)
i = i * 2;
}
答案:O()
(2)冒泡排序的最坏情况下的时间复杂度
for(int i = n - 1; i > 1; i--){
for(int j = 1; i < i; j++){
if(A[j] > A[j+1])
swap(A[j], A[j+1]);
}
}
答案:O()
(3)求第四行语句的执行次数
int m = 0, i, j;
for(i = 1; i <= n; i++){
for(j = 1; j <= 2 * i; j++){
m++;
}
}
答案:O(n(n+1))
(4)已知两个长度分别为m和n的升序链表,若将它们合并为长度为m+n的降序链表,最坏情况下的时间复杂度是?
答案:O(max(m,n))
我的理解:采用头插法建立新链表,两个链表逐个比较,每次比较确定一个元素的位置,由于指针移动次数相同,则根据比较次数确定时间复杂度确定时间复杂度。最坏情况为每个元素都要比较,需要比较m+n-1次,此时根据加法规则,最坏的时间复杂度为O(max(m,n)),最好情况为短链表中的元素都比长链表中的小,则其时间复杂度为O(min(m,n))。
(5)一个算法所需的时间由下递归方程表示,求时间复杂度的阶
答案:O(n)
我的理解:递归可直接写出递推关系式,从而计算出时间复杂度,得出答案应是n(+1),根据加法规则,即为n
。