算法的时间复杂度分析
算法分析
- 算法分析即指对一个算法所需要的资源进行预测 内存,通信带宽或者计算机硬件等资源偶尔是我们关心的
- 通常,资源是指我们希望测度的计算时间
RAM模型
- 分析一个算法之前,需要建立一个实现技术的模型,包括描述所用资源及其代价的模型
- RAM模型:单处理器,随机存取RAM 指令一条接一条地执行,没有并发操作(单处理器)
- 包含真实计算机中的常见指令:算术,数据移动,控制
- 每条指令所需时间为常量
- 数据类型为整型和浮点型
算法运行时间
- 运行时间取决于输入的内容 相同规模\(n\),不同的序列有不同的运行时间,比如逆序序列或者顺序序列
- \(n\)越大,时间自然越多
通常我们关心运行时间的上限(最坏情况)
注:我们分析时间时要使用机器独立的时间单位,即不考虑机器不同带来的影响。
插入排序时间分析
- 假设每行每次执行的时间为常量\(c_i\)
for j: 2 to length[A]:
do key = A[j]
i = j-1
while i>0 and A[i]>key
do A[i+1] = A[i]
i = i-1
A[i+1] = key
[/code]
\(cost:c_1;times:n\) (包含跳出循环的那次)
注:for循环是刚刚进入循环时就要判断一次条件,然后再执行
j--
,再判断条件,直到判断条件不满足,不进入循环。假设循环\(n\)个元素,实际执行\(n+1\) 次比较\(cost:c_2;times:n-1\)
\(cost:c_3;times:n-1\)
\(cost:c_4;times:\sum\limits_{j=2}^nt_j, t_j\) 为一次for循环中while循环的判断次数
\(cost:c_5;times:\sum\limits_{j=2}^n(t_j-1),\)
\(cost:c_6;times:\sum\limits_{j=2}^n(t_j-1)\)
\(cost:c_7;times:n-1\)
\(t_j\) 取决于与序列排序情况有关,如果已经排好序了,\(A[j-1]\)总是小于key了,所以每次for循环只算判断了一次while,总共\(n-1\)次,如果是逆序,前一个总比后一个大,满足while条件,每次for循环中while判断次数为\(t_j=j-1+1=j\) ,总共\(\sum\limits_{j=2}^n{t_j}\) 次。
总的运行时间:
\(T(n)=c_1n+c_2(n-1)+c_3(n-1)+c_4\sum\limits_{j=2}^n{t_j}+c_5\sum\limits_{j=2}^n(t_j-1)+c_6\sum\limits_{j=2}^n(t_j-1)+c_7(n-1)\)
渐进分析
- 如果一个算法的最坏情况运行时间要比另一个算法的低,我们就常常认为它的效率更高。那么如何比较两个算法的运行时间呢?
- 渐进表示:忽略每条语句的真实代价,而用常量\(c_i\) 表示,只考虑公式中的最高次项(低阶项相对来说不太重要),忽略最高次项的常数系数(对于增长率而言,系数是次要的) 在输入的规模较小时,由于常数项和低次项的影响,这种看法有时可能是不对的。对规模足够大的输入来说,这种看法总是对的。
渐进符号
\(\Theta(g(n))=\{f(n):存在正常数c_1,c_2,n_0,对所有的n\ge{n_0},有0\le{c_1g(n)\le{f(n)}\le{c_2g(n)}}\}\)
- \(\Theta(g(n))\) 是一个集合,记号\(f(n)=\Theta(g(n))\) 是指\(f(n)\) 是这个集合中的一个元素,不是指相等
具体来说:当\(n\)大于某个数时,一个与\(n\)有关的函数\(f(n)\),不管\(n\)如何增长,其大小总是被限制到\(c_1g(n)\)和 \(c_2g(n)\)之间。
- 在时间复杂度分析中,\(f(n)\)即我们所要求的\(T(n)\),当我们不需要精确地求出\(T(n)\)时,我们只需要大致知道它随\(n\)增长时,其值的上下界如何,即这个算法的运行时间肯定不会超过某个时间,不会低于某个时间。
- 比如:\(T(n)=\Theta(n^2)\) 表示该算法的运行时间不会超过\(c_1n^2\) ,不会低于\(c_2n^2\) \(\Theta(n^2)\) 是所有满足该性质的算法的\(T(n)\) 的集合
\(O(g(n))=\{f(n):存在正常数c,n_0,对所有的n\ge{n_0},有0\le{f(n)}\le{cg(n)}\}\)
- 描述了算法运行的上界,不会超过常数倍的\(g(n)\) ,即最坏情况
- 比如 \(T(n)=O(n^2)\) 表示该算法运行时间不会超过\(cn^2\)
\(\Omega(g(n))=\{f(n):存在正常数c,n_0,对所有的n\ge{n_0},有0\le{cg(n)}\le{f(n)}\}\)
- 描述算法运行的下界,表示不低于常数倍\(cg(n)\)
一个渐进正函数中的低阶项和最高阶项的系数在决定渐进确界(上界、下界)时可以被忽略
分治算法分析
分治法在每一层递归上都有三个步骤:
分解:将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题;
解决:若子问题规模较小而容易被解决则直接解,否则递归地解各个子问题;
合并:将各个子问题的解合并为原问题的解。
另外,分解到什么规模就够了呢?即分解到子问题可以找到一个方法,使得在线性时间/常量时间内就可以解决。比如归并排序问题,排序到什么时候最容易解决呢?当然是分解到序列内只有一个元素
分治法的递归式
\(T(n)\) 为规模为\(n\)的问题的运行时间,\(D(n)\)为分解问题所需时间,\(C(n)\) 为合并解所需时间
\[ T(n)=\begin{cases} \Theta(1) & n\le{c} \\ aT(n/b)+D(n)+C(n) & otherwise \\ \end{cases} \]
- 第一个式子就是分解到什么规模可以通过\(O(1)\)时间来解决,第二个式子描述的就是子问题的运行时间加上归并所需要的时间
\[ T(n)=\begin{cases} \Theta(1) & n=1 \\ \underbrace{2T(n/2)}_{对两个子序列排序}+\underbrace{\Theta(n)}_{合并解} & n>1 \\ \end{cases} \]
递归式求解
\[ T(n)=\begin{cases} \Theta(1) & n=1 \\ 2T(n/2)+\Theta(n) & n>1 \\ \end{cases} \]
注意问题:
- 假设自变量为整数
- 忽略边界条件
- 忽略上取整,下取整的影响,先假设总能够被整除,等得到结果后再确定他们是否重要
代换法
- 猜测解的形式
- 用数学归纳法找出使解真正有效的常数
- 仅仅适用于解的形式很容易猜的时候
递归树
- 将递归式转换成树形结构,树中的节点代表在不同递归层次付出的代价,利用对和式限界的技术解出递归式
主方法
- 给出递归形式\(T(n)=aT(n/b)+f(n)\)的界,其中\(a≥1,b>1,f(n)\)是给定的函数
转载于:https://www.cnblogs.com/doragd/p/11298698.html
- 算法时间复杂度分析基础
- 归并排序的改进算法(使用静态链表)的时间复杂度分析
- 算法时间复杂度分析基础
- 算法时间复杂度分析基础
- 算法的是时间复杂度分析
- 对高效率素数求解算法进行时间复杂度分析
- 一个台阶总共有n级,如果一次可以跳1级,也可以跳2级。 求总共有多少总跳法,并分析算法的时间复杂度。
- 算法的时间复杂度分析
- 算法——时间复杂度分析方法
- ACM算法-时间复杂度分析(5.有关时间复杂度递归的分析)
- 轮廓问题/Outline Problem-->改进的算法及时间复杂度分析
- 算法时间复杂度分析
- LeetCode "Palindrome Partitioning"算法时间复杂度分析
- 代数运算3(算法的时间复杂度分析)
- ACM算法-时间复杂度分析(6.相关练习exercise)
- MIT:算法导论——4.2快速排序 以及 排序算法时间复杂度分析
- 时间复杂度标记与分析(算法分析与设计)
- [置顶] 【数据结构】算法时间复杂度分析
- 算法导论 时间复杂度分析
- 排序算法的C语言实现以及各个算法的时间复杂度和空间复杂度分析(冒泡排序)