算法分析和抽象数据类型👀
约 1248 个字 14 行代码 预计阅读时间 4 分钟
Perface👀
- clock() :捕捉从程序开始运行到 clock() 被调用所耗费的时间。
- 这个时间单位是 clock tick ,即”时钟打点“。
- 常数 CLK_TCK :机器时钟每秒所走的时钟打点数。
Note
简介->什么是数据结构👀
数据对象在计算机中的组织方式👀
逻辑结构👀
- 一对一的结构,叫做”线性结构“
- 一对多的逻辑结构,叫做”树型结构“
- 多对多的复杂关系网,这个关系网叫做”图“
物理存储结构 (如数组形式、链表形式 ···👀
Note
描述数据结构
抽象数据类型 (Abstract Data Type) | ADT
- 数据类型
- 数据对象集
- 数据集合相关联的操作集
- 抽象:描述数据类型的方法不依赖于具体实现
- 与存放和数据的机器无关
- 与数据存储的物理结构无关
- 与实现操作的算法和编程语言均无关
- 只描述数据对象集和相关操作集”是什么“,并不涉及”如何做到“的问题
- 其中的抽象可以从如下看
- e.g:ElementType 是通用数据类型 (抽象),需要 double ,在前面 define 即可
- e.g:矩阵是用二维数组、一维数组还是十字链表实现的都不重要,只是实现一个矩阵
- e.g:Matrix Add 中不在乎按行加还是按列加,用什么语言实现都不在乎
抽象的好处->一方面是提高程序的复用性,另一方面,让我们侧重去了解程序的逻辑结构
算法分析👀
定义👀
算法 (Algorithm)👀
- 一个有限指令集
- 接受一些输入 (有些情况下不需要输入)
- 产生输出
- 一定在有限步骤之后终止
- 每一条指令必须
- 有充分明确的目标,不可以产生歧义
- 计算机能处理的范围之内
- 描述应不依赖于任何一种计算机语言及具体的实现手段
衡量算法的两个指标👀
空间复杂度 S(n)👀
根据算法写成的程序在执行时 占用存储单元的长度 。这个长度往往与输入数据的规模有关。空间复杂度过高的算法可能导致使用的内存超限,造成程序非正常中断。
时间复杂度 T(n)👀
根据算法写成的程序在执行时 耗费时间的长度 。这个长度往往也与输入数据的规模有关。
复杂度的渐进表示法👀
-
\(T(n) = O (f(n))\) 表示存在常数 \(C>0, n_0 > 0\), 使得当 \(n \ge n_0\) 时有 \(T(n) \le C×f(n)\)
-
\(T(n) =\Omega(g(n))\) 表示存在常数 \(C>0,n_0>0\), 使得当 \(n \ge n_0\) 时有 \(T(n) \ge C×g(n)\)
-
\(T(n) =\Theta(h(n))\) 表示同时有 \(T(n) = O(h(n))\) 和 \(T(n) = \Omega(h(n))\)
TIPs👀
-
若有两段算法分别有复杂度 \(T_1(n) = O(f_1(n))和T_2(n) = O(f_2(n))\),则
-
\(T_1(n) + T_2(n) = max(O(f_1(n)), O(f_2(n)))\) 表示两个算法拼接起来
-
\(T_1(n) \times T_2(n) = O(f_1(n) \times f_2(n))\) 表示两个算法嵌套起来
-
-
若 \(T(n)\) 是关于n的k阶多项式,那么 \(T(n)= \Theta (n^k)\)
-
一个for循环的时间复杂度等于循环次数乘以循环体代码的复杂度
-
if-else结构的复杂度取决于if的条件判断复杂度和两个分支部分的复杂度,总体复杂度取三者中最大
Checking Your Analysis👀
-
Method 1
-
When \(T(N) = O(N)\), check if \(T(2N)/T(N)\approx 2\)
-
When \(T(N) = O(N^2)\), check if \(T(2N)/T(N)\approx 4\)
-
When \(T(N) = O(N^3)\), check if \(T(2N)/T(N)\approx 8\)
-
···
-
-
Method 2
- When \(T(N) = O(f(N))\), check if \(\lim\limits_{N\rightarrow\infty}\frac{T(N)}{f(N)} \approx Constant\)
Info
一个分析复杂度的方法
主定理 | Master👀
介绍👀
Master定理,又称主定理,用于程序的时间复杂度计算 (常用于递归调用算法的时间复杂度)
用法👀
递归算法时间复杂度形如:
-
\(T(n) = O(1), n = 1\)
-
\(T(n) = aT(\frac{n}{b}) + f(n) , n > 1\)
其中,\(a \ge 1; b > 1 ;\)\(f(n)\) 表示不参与递归部分的时间复杂度, 规定 \(C_{crit}=log_ba\)
第二条公式表示:将一个规模为n的问题分为 \(a\) 个规模为 \(\frac{n}{b}\) 子问题,每次递归将带来 \(f(n)\) 的额外计算,然后通过对这 \(a\) 个子问题的解的综合,得到原问题的解
那么有:
- 当 \(f(n) = O(n^c)\) ,且 \(c < C_{crit}\) 时有: \(T(n) = \Theta(n^{C_{crit}})\)
Example
\(T(n) = 8T(\frac{n}{2}) + 1000n^2\)
此时 \(a=8, b=2, f(n)=1000n^2\)
\(c=2<3=log_ba=C_{crit}\)
故 \(T(n)=\Theta(n^3)\)
- 当 \(f(n)=O(n^c)\) , 且 \(c > C_{crit}\) 时有:\(T(n)=\Theta(f(n))\)
Example
\(T(n) = 2T(\frac{n}{2}) + n^2\)
此时 \(a=2, b=2, f(n)=n^2\)
\(c=2 > 1=log_ba=C_{crit}\)
故 \(T(n)=\Theta(n^2)\)
-
当 \(f(n)=O(n^c)\) , 且 \(c=C_{crit}\) 时:\(T(n)=\Theta(n^clog~n)\)
-
若存在非负整数 \(k\) ,使得 \(f(n)=\Theta(n^{C_{crit}}log_kn)\) ,那么 \(T(n)=\Theta(n^{C_{crit}}log_{k+1}n)\)