目录
【数据结构与算法第二章(理论知识)】绪论
1.1 数据结构的定义
数据结构没有一个统一的官方定义,以下是一些经典书籍对数据结构的定义:
① 数据结构是相互之间存在一种或多种特定关系的数据元素的集合;
② 数据结构是数据对象,以及存在于该对象的实例和组成实例的数据元素之间的各种联系。这些联系可以通过定义相关的函数来给出;
③ 数据结构是抽象数据类型( Abstract Data Type,简称 ADT )的物理实现。ADT 是指一个数学模型以及定义在此数学模型上的一组操作。
④ 数据结构是计算机存储和组织数据的方式。精心选择的数据结构可以带来更高的运行或者存储效率。
数据结构的组成 | 定义 | 常见示例 |
数据的逻辑结构 | 从具象问题中抽象出来的,描述数据之间逻辑关系的、与数据存储无关的数学模型 | 如:线性表、树、图 |
数据的物理结构 | 数据的逻辑结构在计算机中的存储实现 | ① 顺序存储结构:利用数据元素在存储器中的相对位置来表示元素之间的逻辑关系,通常用数组实现 ② 链式存储结构:一种数据元素的逻辑地址相邻但物理地址不一定相邻的存储结构。通过链表中指针的链接次序来表示数据元素之间的逻辑顺序 ③ 散列存储结构:根据元素的关键字通过散列函数计算出的一个值,并将这个值作为该元素的地址 |
数据的运算 | 对数据实施的操作 | 对数据进行增删改查和排序等 |
1.2 算法的基本概念
- 算法的几种经典定义:
① 算法是对特定问题求解步骤的一种描述,在计算机中表现为指令的有限序列;
② 算法是精确定义一系列操作的一套规则;
③ 算法是为了解决某类问题而规定的一个有限长的操作序列;
④ 算法是任何良定义的计算过程,该过程去某个值或值的集合作为输入并产生某个值或值得集合作为输出。也就是说,算法是描述计算机如何将输入转化为所要求的输出的过程。
- 算法必备五要素:
① 有穷性:在执行有限次基本操作后结束;
② 确定性:在算法中明确规定了每种情况应该执行的操作。相同的输入得到相同的输出,不存在二义性;
③ 可行性:算法由若干语义明确的基本操作组成。算法中所有的操作均可调用有限次基本操作来实现;
④ 输入:可理解为对所求特定问题的描述。一个算法可以有零个或者多个输入;
⑤ 输出:可理解为输入的问题经过算法的处理之后得到的求解结果。算法至少有一个输出。
- 算法好坏的评价标准:
① 正确性:执行算法后能得到预期的效果。这是算法最基础的功能;
② 用户友好性:算法应方便使用,便于理解、修改和调试;
③ 健壮性:具备对异常情况的处理;
④ 高效率性:执行效率高,合理占用存储空间。
1.3 算法效率分析
算法效率的衡量标准就是时间复杂度和空间复杂度。
1.3.1 时间复杂度
- 定义:
首先先了解几个相关名词:
① 问题规模 n 表示算法的输入量。可以理解为数据量的大小。比如,在排序算法中,问题规模 n 指参与排序的数据个数,在树相关运算中,问题规模 n 指节点的个数;
② 语句频度指一条语句的重复执行次数;
③ 基本语句指对算法运行时间影响最大的语句;
④ 用函数 f(n) 表示一个算法中基本语句的语句频度之和。
时间复杂度( Time Complexity ),常用函数 T(n) 表示,指基本语句执行次数的数量级。通常用符号O( order 的缩写)表示取数量级的操作,T(n)=O(f(n)).
Notice:一个算法中所有语句频度之和与基本语句的频度之和是同一个数量级。
- 时间复杂度的计算:
① 找到所有语句中执行次数最多的那条语句作为基本语句;
② 计算基本语句执行次数的数量级;
③ 取其数量级,用O表示。
示例如下:
A: A[0][0]++; T(n) = O(1)
B: for(int i = 0; i < n; i++) A[i][i] += 2; T(n) = O(n)
C: for(int k = 0; k < n; k++)
for(int j = 0; j < n; j++)
++A[k][j]; T(n) = O(n^2)
- 时间复杂度的分类:
算法的时间复杂度不仅与问题的规模n有关,还和其他因素有关,如初始状态等。
① 在算法计算量最小的情况下的复杂度称为最好时间复杂度;
② 在算法计算量最大的情况下的复杂度成为最坏时间复杂度;
③ 在所有可能情况下,各种输入情况等概率出现,算法的计算量取加权平均值,在该情况下的复杂度称为平均时间复杂度。
Notice:通常,时间复杂度默认为最坏时间复杂度。
- 常用时间复杂度大小比较:
O(1) < O(log n) < O(n) < O(nlog n) < O(n^2) < O(n^3) < O(2^n) < O(n!) < O(n^n)
Notice:任意底数的对数复杂度都是同阶的,如O(lg n) = O(ln n)
- 时间复杂度的相关总结:
① 递归算法的时间复杂度计算方法比较固定,比如,
则T(n) = T(n-1) + 1 = T(n-2) + 2 = ... =T(1) + n - 1,所以时间复杂度为O(n);
② 基本操作:只有常数项,时间复杂度为O(1);
③ 顺序结构:时间复杂度按加法规则进行相加;
④ 分支结构:时间复杂度按最坏情况下的时间复杂度计算;
⑤ 循环结构:时间复杂度按乘法规则进行计算;
⑥ 分析具体算法的时间复杂度时,一般分析最坏情况的时间复杂度;
⑦ 利用时间复杂度判断算法的效率高低时,只需关注基本操作的最高次项即可,如O(n^2 + 2^n),则以指数阶作为时间复杂度;
⑧ 加法规则:T(n) = O(h(n)) + O(f(n)) = O(max(h(n), f(n)));
⑨ 乘法规则:T(n) = O(h(n)) * O(f(n)) = O(h(n) * f(n))。
1.3.2 空间复杂度
- 算法占用存储空间的三部分:
① 存储程序本身的空间:比如具体的程序代码;
② 存储算法输入和输出数据的空间:与问题规模n有关;
③ 对数据进行辅助操作的临时变量所占存储空间:分析算法的空间复杂度就是分析该部分的空间。
- 定义:
空间复杂度( Space Complexity )是对一个算法在运行过程中临时占用存储空间大小的量度。
若问题规模为n,f(n) 是算法运行过程中需要的辅助存储空间的函数,符号O(order的缩写)表示取数量级的操作。用 S(n) 表示空间复杂度,则 S(n) = O(f(n)).
Notice:若算法在运行过程中占用的临时空间为常数级别(即O(1)),则称算法是原地工作的。