结论:判断一个算法的效率时,操作数量中的常数项和其他次要项常常可以忽,只需要关注最高阶次项就能得出结论

问题:如何用符号定性的判断算法的效率?

算法的复杂度(定性描述)

  • 时间复杂度

    • 算法运行后对时间需求量的定性描述
  • 空间复杂度

    • 算法运行后对空间需求量的定性描述

注意:数据结构课程重点关注的是算法的效率问题,因此,整个课程会集中于讨论算法的时间复杂度;但其使用的方法完全可以用于空间复杂度的判断。

大O表示法

  • 算法效率严重依赖于操作(Operation)数量
  • 操作数量的估算可以作为时间复杂度的估算
  • 在判断时优先关注操作数量的最高次项

常见的时间复杂度

  • 线性时间复杂度:O(n)
void func()
{
    for (int i=0; i<n; ++i)  // 循环次数: n
    {
        // 复杂度为 O(1) 的程序语句
    }
}
  • 对数阶时间复杂度: O(logn)
void func()
{
    int i = 1;
    while (i < n)  // 循环次数:log2n (2为底数)
    {
        // 复杂度为 O(1) 的程序语句
        i *= 2;
    }
}
  • 平方阶时间复杂度: O(n2)
void func()
{
    for (int i=0; i<n; ++n)  // 循环次数:n2 (2为指数)
    {
        for (int j=0; j<n; ++j)
        {
            // 复杂度为 O(1) 的程序语句
        }
    }
}

时间复杂度计算练习

  1. 下面代码的时间复杂度是什么?
for (int i=0; i<n; ++i)  // O(n2) (2为指数)
{
    for (int j=i; j<n; ++j)
    {
        // 复杂度为 O(1) 的程序语句
    }
}
i = 0     => n
i = 1     => n - 1
i = 2     => n - 2
...
i = n - 1 => 1

==> n + (n-1) + (n-2) + ... + 1 = n(n+1)/2
==> O(n(n+1)/2)  
==> O(n2) (2为指数)
  1. 函数func()的时间复杂度是什么?
void t(int n)       // O(n)
{
    int i = 0;
    while (i < n)
    {
        cout << i << endl;
    }
}

void func(int n)    // O(n(n+1)) => O(n2) (2为指数)
{
    int i = 0;
    
    while (i < n)
    {
        t(n)       // O(n)
        ++i;       // O(1)
    }
}
  1. 函数 test() 的时间复杂度是什么?
void test(int n)            // O(n + n2 + n3) ==> O(n3) (3为指数)
{
    t(n);                   // O(n)
    
    for (int i=0; i<n; ++i) // O(n2)
        t(i);
        
    for (int i=0; i<n; ++i) // O(n3)
        for (int j=i; j<n; ++j)
            t(i);
}

小结

  • 时间复杂度是算法运行时对于时间的需求量
  • 大O表示法用于描述算法的时间复杂度
  • 大O表示法只关注操作数量的最高次项
  • 常见的时间复杂度为:线性阶,平方阶和对数阶

以上内容整理于狄泰软件学院系列课程,请大家保护原创!


TianSong
734 声望138 粉丝

阿里山神木的种子在3000年前已经埋下,今天不过是看到当年注定的结果,为了未来的自己,今天就埋下一颗好种子吧