数据结构与算法系列——时间、空间复杂度

数据结构和算法本质就是帮我们用最快的时间和最少的空间来执行我们的代码。所以,执行效率是衡量一个算法的非常重要的指标。那如何来计算你的算法代码的执行效率呢?这就需要时间、空间复杂度来分析了。

有人可能会说,我把代码执行一遍,然后通过统计、监控就能知道执行的时间和需要的内存大小。干嘛还需要时间、空间复杂度来分析呢?我都能得到具体需要的时间和内存了,还需要多此一举吗?

首先,这种评估算法效率的方法没有问题,我们还给这种方法起了一个名字,叫事后统计法。但是这种方法有很大的局限性。

1. 测试结果受测试环境影响

测试环境的硬件对测试结果有非常大的影响。比如,同样的代码在i7和i5的机器上执行,结果肯定是不同的。还有可能在一台机器上A代码比B代码执行速度要快,我们换另外一台机器却得到相反的结果。

2. 测试结果受数据规模的影响

比如排序算法,原始数据如果有序度不一样,执行的时间就会有很大的差别。原始数据规模的大小不同,也可能会让原来速度快的算法变成速度慢的。

所以我们就需要一个不需要具体的测试数据来测试,就可以大概估算出执行效率的方法,就是时间、空间复杂度分析方法。

大O复杂度表示方法

我们通过度代码,来估算出它执行所需要的时间,下边来看一段具体的代码。

public int Function(int n)
{
    int sum = 0;
    for(int i = 1; i <= n; i++)
    {
        sum += i;
    }
    return sum;
}

这里我们假设每一行代码执行的时间都是相同的为 t,那么第 3 行执行的时间为 t,第 4 和 6 行执行了 n 次,需要时间为 2nt,总的时间为 (1+2n)t,可以看出来总的代码的执行时间 T(n) 与每行代码的执行次数成正比。

然后我们再来看下边的代码

public int Function(int n)
{
    int sum = 0;
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n; j++
        {
            sum += i*j;
        }
    }
    return sum;
}

这段代码中在上边的基础上又套了一层 for 循环,第 6 和 8 行执行了 n^2 次,需要的时间为 2n^2 * t,总的需要的时间为 T(n)=(2n^2+2n+1) * t

通过上述两个具体的代码例子我们总结出一个公式:
T(n)=O(f(n))
T(n) 表示代买执行的时间,n 是数据的大小,f(n) 表示代码执行的总次数,O 表示公式中 T(n) 与 f(n) 成正比。这就是大 O 时间复杂度表示法,它实际上并不表示代码具体执行所需要的时间,它表示随着数据规模的变化代码执行时间的变化趋势。

当 n 非常大时,低阶、系数、常量对结果的影响就非常小了,所以我们可以把这几项忽略不记,只保留最高阶的就可以了,所以上边两个例子中 O(1+2n) 就可以记为O(n)O(2n^2+2n+1) 就可以记为 O(n^2)

上边我们知道了怎么用大 O 时间复杂度的表示方法。那么我们如何具体分析一段代码的时间复杂度呢?

  • 只关注循环次数最多的一段代码

因为大 O 时间复杂度只表示一种变化的趋势,所以我们只需要关心阶数最高的那部分就可以了,低阶、系数、常量我们都可以忽略。以上边第一段代码为例 O(1+2n),我们忽略掉系数和常量最后就得到了O(n)

  • 加法法则

对于顺序执行的长代码,我们把它分成几部分,分别求出其总时间 T(n) ,然后相加得到总的时间,最后同样忽略低阶、系数、常量部分,保留最高阶的部分然后得出最后的时间复杂度大 O。

  • 乘法法则

对于逻辑复杂的嵌套代码,我们分别求嵌套内外代码的复杂度,然后相乘得出最终的时间复杂度大 O。

几种常见的时间复杂度分析

下边列举出常见的时间复杂度量级

多项式量级 非多项式量级
常数阶 O(1) 指数阶 O(2^n)
对数阶 O(logn) 阶乘阶 O(n!)
线性阶 O(n)
线性对数阶 O(nlogn)
k次方阶 O(n^2) O(n^3) O(n^k)

对于非多项式量级的算法会随着数据规模的增大急剧增加,所以分多项式量级的算法是非常低效的,我们不做过多的介绍。主要来介绍几种常见的多项式量级的时间复杂度。

  1. 常数阶 O(1)

O(1) 只是常量级时间复杂度的表示方式,不是只有一行代码,而是每一段代码的执行时间不随着 n 的数据规模的变大而变长,这样的代码的时间复杂度记为 O(n)

  1. 对数阶 O(logn) O(nlogn)

对数阶复杂度很常见,但是分析的时候却不容易,下面我们用一段实际的例子来看看对数阶时间复杂度。

public void Function(int n)
{
    int i = 1;
    while(i<=n)
    {
        i = i*2;
    }
}

通过上边我们总结的方法,我们只需要知道 while 循环的次数,就能得到这段代码的复杂度。从代码中可以看出 i 的值从 1 开始,每循环一次乘以 2,直到 i 的值大于 n 的时候结束,我们得到规律然后把结果列出来,
2^0 2^1 2^3 2^4 …… 2^x = n ,然后求得执行的次数 x = logn ,这段代码的时间复杂度就是 O(logn)

  1. O(n+m) O(n*m)

我们再来讲一种跟前面都不一样的时间复杂度,代码的复杂度由两个数据的规模决定,所以我们需要同时考虑两种数据规模对结果的影响,如果是顺序的,那么时间复杂度就为 O(n+m),如果为嵌套的那么时间复杂度为 O(n*m)

空间复杂度分析

理解了上边的时间复杂度的分析方法,空间复杂度的分析也就很简单了。空间复杂度表示算法的存储空间与数据规模之间的增长关系。

同样我们通过一段实际的代码来分析一下。

public void Function(int n)
{
    int i = 0;
    int[] a = new int[n];
    for(i;i<n;i++)
    {
        a[i] = i*i;
    }
}

我们看到第 3 行代码,我们申请了一个空间存储变量 i ,但是这个是常数阶的,不会随 n 的变化而变化,所以可以忽略,第 4 行我们申请了一个大小为 n 的 int 类型数组,除此之外其余代码没有占用其他的空间,所以这段代码的空间复杂度为 O(n)

我们常见的空间复杂度有 O(1)O(n)O(n^2),对数阶的空间复杂度一般情况下用不到。所以空间复杂度比时间复杂度容易分析的多,我们也只需要掌握常见的几种就可以了。

最后我们总结一下常见的几种复杂度,执行效率从高到低依次为
O(1)>O(logn)>O(n)>o(nlogn)>O(n^2)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容