• 算法的时间复杂度分析


    算法分析

    • 算法分析即指对一个算法所需要的资源进行预测
      • 内存,通信带宽或者计算机硬件等资源偶尔是我们关心的
      • 通常,资源是指我们希望测度的计算时间

    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
    
    1. (cost:c_1;times:n) (包含跳出循环的那次)

      注:for循环是刚刚进入循环时就要判断一次条件,然后再执行j--,再判断条件,直到判断条件不满足,不进入循环。假设循环(n)个元素,实际执行(n+1) 次比较

    2. (cost:c_2;times:n-1)

    3. (cost:c_3;times:n-1)

    4. (cost:c_4;times:sumlimits_{j=2}^nt_j, t_j) 为一次for循环中while循环的判断次数

    5. (cost:c_5;times:sumlimits_{j=2}^n(t_j-1),)

    6. (cost:c_6;times:sumlimits_{j=2}^n(t_j-1))

    7. (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) ,总共(sumlimits_{j=2}^n{t_j}) 次。

    总的运行时间:

    (T(n)=c_1n+c_2(n-1)+c_3(n-1)+c_4sumlimits_{j=2}^n{t_j}+c_5sumlimits_{j=2}^n(t_j-1)+c_6sumlimits_{j=2}^n(t_j-1)+c_7(n-1))

    渐进分析

    • 如果一个算法的最坏情况运行时间要比另一个算法的低,我们就常常认为它的效率更高。那么如何比较两个算法的运行时间呢?
    • 渐进表示:忽略每条语句的真实代价,而用常量(c_i) 表示,只考虑公式中的最高次项(低阶项相对来说不太重要),忽略最高次项的常数系数(对于增长率而言,系数是次要的)
      • 在输入的规模较小时,由于常数项和低次项的影响,这种看法有时可能是不对的。对规模足够大的输入来说,这种看法总是对的。
    • 虽然有时候能够精确确定一个算法的运行时间,但通常没有必要。(在RAM模型下,可以精确计算T(n))
    • 渐近分析更有意义(对不是很小的输入规模而言,从渐进意义上说更有效的算法就是最佳的选择)

    渐进符号

    (Theta(g(n))={f(n):存在正常数c_1,c_2,n_0,对所有的nge{n_0},有0le{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,对所有的nge{n_0},有0le{f(n)}le{cg(n)}})

    • 描述了算法运行的上界,不会超过常数倍的(g(n)) ,即最坏情况
    • 比如 (T(n)=O(n^2)) 表示该算法运行时间不会超过(cn^2)

    (Omega(g(n))={f(n):存在正常数c,n_0,对所有的nge{n_0},有0le{cg(n)}le{f(n)}})

    • 描述算法运行的下界,表示不低于常数倍(cg(n))

    一个渐进正函数中的低阶项和最高阶项的系数在决定渐进确界(上界、下界)时可以被忽略

    分治算法分析

    • 分治法在每一层递归上都有三个步骤:

      分解:将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题;

      解决:若子问题规模较小而容易被解决则直接解,否则递归地解各个子问题;

      合并:将各个子问题的解合并为原问题的解。

    • 另外,分解到什么规模就够了呢?即分解到子问题可以找到一个方法,使得在线性时间/常量时间内就可以解决。比如归并排序问题,排序到什么时候最容易解决呢?当然是分解到序列内只有一个元素

    • 分治法的递归式

      • (T(n)) 为规模为(n)的问题的运行时间,(D(n))为分解问题所需时间,(C(n)) 为合并解所需时间

    [T(n)=egin{cases} Theta(1) & nle{c} \ aT(n/b)+D(n)+C(n) & otherwise \ end{cases} ]

    • 使用分治法的归并排序的递归式
      • 第一个式子就是分解到什么规模可以通过(O(1))时间来解决,第二个式子描述的就是子问题的运行时间加上归并所需要的时间

    [T(n)=egin{cases} Theta(1) & n=1 \ underbrace{2T(n/2)}_{对两个子序列排序}+underbrace{Theta(n)}_{合并解} & n>1 \ end{cases} ]

    递归式求解

    [T(n)=egin{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))是给定的函数


  • 相关阅读:
    GMap.NET 随谈
    Chrome Uncaught Error: NETWORK_ERR: XMLHttpRequest Exception 101
    Java 自定义枚举
    如何得到全国省市经纬度范围
    Jquery formwizard 入门 【前台 向导功能】
    Eclipse Juno 安装 Aptana 3.3,支持jquery智能提示
    Ant学习【实践1】
    euerka总结 当幸福来敲门
    Spring Boot 热启动插件 当幸福来敲门
    ASP.NET 2.0 Provider Model 详细分析
  • 原文地址:https://www.cnblogs.com/doragd/p/11298698.html
Copyright © 2020-2023  润新知