比较基础的入门知识点中,时间复杂度和空间复杂度的计算、算法的设计是主要的考察点。
逻辑结构是指数据元素之间的逻辑关系。它与数据的存储结构无关,同一种逻辑结构可以有多种存储结构。线性表是典型的线性结构;集合、树和图是典型的非线性结构。数据的逻辑结构分类见图。
线性结构是一个数据元素的有序集合,有3个基本特征:
数据元素(在树中称为结点)按分支关系组织起来的结构,很象自然界中的树那样。结构中的元素存在着“一对多”的关系。
“多对多”关系形成的逻辑结构。其中每个元素的直接前趋和直接后继数目都不限。
数据的存储结构是其逻辑结构在计算中的表示(映像),也可以理解为数据的存储结构是用计算机语言实现的逻辑结构,它依赖于计算机语言数据的逻辑结构。它包括数据元素的表示和关系的表示。当数据元素是由若干项数据构成的时候,数据项的表示称为数据域。
数据元素之间的关系在计算机中有两种不同的表示方法:顺序映像和非顺序映像(从逻辑关系上分类)。对应两种不同的存储结构:顺序存储结构和链式存储结构。顺序映像借助数据元素在内存中的相对位置来表示它们之间的逻辑关系;非顺序映像借助的则是指针。
把逻辑上相邻的元素存储在物理位置上相邻的存储单元中,元素之间的关系由存储单元的邻接关系来体现。优点是可以实现随机存取,每个元素占用最少的存储空间;缺点是只能使用相邻的一整块存储单元,因此可能产生较多的外部碎片。
不要求逻辑上相邻的元素在物理位置上也相邻,借助指示元素存储地址的指针表示元素之间的逻辑关系。优点是不会出现碎片现象,充分利用所有存储单元;缺点是每个元素因存储指针而占用额外的存储空间,并且只能实现顺序存取。值得注意的是,链式存储的结点的存储空间可以不连续,但是结点内的存储单元地址必须是连续的。
在存储元素信息的同时,还建立附加的索引表来标致数据元素的地址。索引表中的每一项称为索引项,索引项的一般形式是:<关键字,地址>,地址作为指向数据元素的指针。优点是检索速度快;缺点是增加了附加的索引表,会占用较多的存储空间。另外,在增加和删除数据时要修改索引表,因而会花费较多的时间。
由数据元素的关键字通过散列函数直接计算出该元素的存储地址,又称为 Hash 存储,本质上是顺序存储方法的扩展。其优点是检索、增加和删除结点的操作都很快;缺点是如果散列函数不好可能出现元素存储单元的冲突,而解决冲突会增加时间和空间开销。
施加在数据上的运算包括运算的定义和实现。运算的定义是针对逻辑结构的,指出运算的功能;运算的实现是针对存储结构的,指出运算的具体操作步骤。
算法是对特定问题求解步骤的一种描述,它是指令的有限序列,其中每一条指令表示一个或多个操作。可以理解为由基本运算及规定的运算顺序所构成的完整的解题步骤
通常将算法中基本操作的执行次数(时间)作为算法时间复杂度的度量。一个语句的频度是指该语句在算法中被重复执行的次数。算法中所有语句的频度之和记作 T ( n ) T(n) T(n),它是该算法问题规模 n n n 的函数,时间复杂度主要是分析 T ( n ) T(n) T(n) 的数量级。算法中的基本运算(最深层循环内的语句)的频度与 T ( n ) T(n) T(n) 同数量级,所以通常采用算法中基本运算的频度 f ( n ) f(n) f(n) 来分析算法的时间复杂度。因此,算法的时间复杂度记为: T ( n ) = O ( f ( n ) ) T(n) = O(f(n)) T(n)=O(f(n))。
上式中“O”的含义是 T ( n ) T(n) T(n) 的数量级,其严格的数学定义是:若 T ( n ) T(n) T(n) 和 f ( n ) f(n) f(n) 是定义在正整数集合上的两个函数,则存在正常数 C C C 和 n 0 n_0 n0,使得当 n ≥ n 0 n \ge n_0 n≥n0 时,都满足 0 ≤ T ( n ) ≤ C × f ( n ) 0 \le T(n) \le C \times f(n) 0≤T(n)≤C×f(n)。
算法的时间复杂度不仅依赖于问题的规模 n n n,也取决于待输入数据的性质(如输入数据元素的初始状态)。例如在数组 A [ 0 … n − 1 ] A[0 … n - 1] A[0…n−1] 中,查找给定值 k k k 的算法如下:
i = n - 1;
while (i >= 0 && (A[i] != k)) {
i--;
}
return i;
此算法中的第三行代码就是基本运算,它的执行频度不仅与问题规模 n n n 有关,还与数组 A A A 中的各元素取值及 k k k 的取值有关:
① 若 A A A 中没有与 k k k 相等的元素,则语句3的频度 f ( n ) = n f(n) = n f(n)=n。
② 若 A A A 的最后一个元素等于 k k k,则语句3的频度 f ( n ) = 0 f(n) = 0 f(n)=0。
补充几个时间复杂度的分类:
一般总是考虑在最坏情况下的时间复杂度,以保证算法的运行时间不会比它更长。
在分析一个程序的时间复杂性时,通常有以下两条规则:
T ( n ) = T 1 ( n ) + T 2 ( n ) = O ( f ( n ) ) + O ( g ( n ) ) = O ( m a x ( f ( n ) , g ( n ) ) ) T(n) = T_1(n) + T_2(n) = O(f(n)) + O(g(n)) = O(max(f(n),\ g(n))) T(n)=T1(n)+T2(n)=O(f(n))+O(g(n))=O(max(f(n), g(n)))
T 1 ( n ) × T 2 ( n ) = O ( f ( n ) ) × O ( g ( n ) ) = O ( f ( n ) × g ( n ) ) T_1(n) \times T_2(n) = O(f(n)) \times O(g(n)) = O(f(n)\times g(n)) T1(n)×T2(n)=O(f(n))×O(g(n))=O(f(n)×g(n))
常用的时间复杂度比较关系:
O ( 1 ) < O ( l o g 2 n ) < O ( n ) < O ( n l o g 2 n ) < O ( n 2 ) < O ( n 3 ) < O ( 2 n ) < O ( n ! ) < O ( n n ) O(1)
算法的空间复杂度 S ( n ) S(n) S(n) 定义为该算法所耗费的存储空间,它是问题规模 n n n 的函数。渐近空间复杂度也简称为空间复杂度,记作 S ( n ) = O ( g ( n ) ) S(n) = O(g(n)) S(n)=O(g(n))。
希望本篇博客能对你有所帮助,也希望看官能动动小手点个赞哟~~。