0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

一文徹底了解時間復(fù)雜度

C語言編程學(xué)習(xí)基地 ? 來源:51CTO ? 作者:慕雪年華 ? 2022-08-27 17:51 ? 次閱讀

算法在編寫成可執(zhí)行程序的時候,main函數(shù)使用這個算法,需要調(diào)用一定的空間,消耗一定的時間。算法的效率就是通過空間和時間這兩個維度來評判的。

時間復(fù)雜度:衡量一個算法的運行速度

空間復(fù)雜度:衡量一個算法運行需要開辟的額外空間

那么我們今天先來看看時間復(fù)雜度!

79c67cb2-25db-11ed-ba43-dac502259ad0.png

時間復(fù)雜度

算法的時間復(fù)雜度是一個函數(shù),它定量描述了該算法的運行時間。算法中基本操作的執(zhí)行次數(shù),為算法的時間復(fù)雜度

時間復(fù)雜度是一個近似值,并不是實際運行的時間

實際上代碼的運行時間,和機器的內(nèi)存、cpu性能和平臺都有關(guān)系,同一個代碼在不同的機器上運行時間都不一樣,如果只以純粹的時間來考核,很難分析

找到某條基本語句與問題規(guī)模N之間的數(shù)學(xué)表達式,就算出了該算法的時間復(fù)雜度

void Test(int N){    int count =0;    for(int i=0;i    {        for(int j=0;j        {            count++;        }    }        for (int k = 0; k < 2 * N ; ++ k)    {        count++;    }        int M = 10;    while (M--)    {        count++;    }        return;}

請問這個代碼中,count語句執(zhí)行了幾次?

F ( N ) = N 2 + 2 ? N + 10 F(N)=N^2+2*N+10 F(N)=N2+2?N+10

N = 10 F(N) = 130

N = 100 F(N) = 10210

N = 1000 F(N) = 1002010

你可能會簡單地認為,F(xiàn)(N)的結(jié)果就是我們的時間復(fù)雜度。其實并不然,我們并不需要一個精確的運行次數(shù),只需要知道程序運行次數(shù)的量級就行了

這里我們使用大O漸進表示法來表示時間復(fù)雜度(空間復(fù)雜度同理)

2.1大O的漸進表示法

大O符號(Big O notation):是用于描述函數(shù)漸進行為的數(shù)學(xué)符號

推導(dǎo)大O階方法:

(1)用常數(shù)1取代運行時間中的所有加法常數(shù)。

(2)在修改后的運行次數(shù)函數(shù)中,只保留最高階項。

(3)如果最高階項存在且不是1,則去除與這個項目相乘的常數(shù)。得到的結(jié)果就是大O階

使用這種方法后,test1函數(shù)的時間復(fù)雜度為

O ( N 2 ) O(N^2) O(N2)

對于test1函數(shù),在計算的時候,我們省略了最后的+10,保留了最高階數(shù)N2,即得出了它的時間復(fù)雜度

如果最高階數(shù)前面有系數(shù),如2N,系數(shù)也將被省略

因為當N的數(shù)值很大的時候,后面的那些值對我們總運行次數(shù)的影響已經(jīng)非常小了。大O的漸進表示法去掉了那些對結(jié)果影響不大的項,簡潔明了的表示出了執(zhí)行次數(shù)

2.2多種情況取最壞

一些算法的時間復(fù)雜度會有最好、最壞和平均的情況

最好情況:任意輸入規(guī)模的最小運行次數(shù)(下界)

平均情況:期望的運行次數(shù)

最壞情況:任意輸入規(guī)模的最大運行次數(shù)(上界)

舉個例子,當我們編寫一個在數(shù)組中查找數(shù)值的算法時,它可能會出現(xiàn)這幾種情況:

最好情況:1次就找到

平均情況:N/2次

最壞情況:N次

在實際中的一般情況,我們關(guān)注的是算法的最壞運行情況,所以數(shù)組中搜索數(shù)據(jù)時間復(fù)雜度為O(N)

2.3常見時間復(fù)雜度的計算

NO.1

void Func1(int N){     int count = 0;     for (int k = 0; k < 2 * N ; ++ k)     {      ++count;     }     int M = 10;     while (M--)     {      ++count;     }  printf("%d
", count);}

這里出現(xiàn)了兩個循環(huán),分別是2N次和10次。前面提到了大O漸進法只保留最高階數(shù)并省略系數(shù),所以它的時間復(fù)雜度是O(N)

NO.2

void Func2(int N, int M){     int count = 0;     for (int k = 0; k < M; ++ k)     {      ++count;     }     for (int k = 0; k < N ; ++ k)     {      ++count;     }     printf("%d
", count);}

這里出現(xiàn)了次數(shù)為N和M的兩層循環(huán):

當M和N差不多大的時候,時間復(fù)雜度可以理解為O(M)或O(N)

當M遠遠大于N時,時間復(fù)雜度為O(M)

一般情況取O(M+N)

NO.3 常數(shù)階

void Func3(int N){     int count = 0;     for (int k = 0; k < 100; ++ k)     {      ++count;     }     printf("%d
", count);}

這里我們得知了具體的循環(huán)次數(shù)為100,是一常數(shù),時間復(fù)雜度為O(1),代表常數(shù)階

只要循環(huán)次數(shù)已知,為一常數(shù)且和所傳參數(shù)無關(guān),其時間復(fù)雜度即為O(1)

NO.4 strchr

//計算strchr的時間復(fù)雜度const char * strchr ( const char * str, int character );

看到這道題的時候,你可能會一愣,strchr是什么?

可這里面沒有strchr,但有strstr

strstr函數(shù)的作用:在字符串1中尋找是否有字符串2

其中第二個str代表的是string字符串,那我們是不是可以猜想,chr代表的是char字符,其作用是在一個字符串中查找是否有一個字符呢?

當然,光是猜想肯定是不夠的,我們還需要求證一下

打開cplusplus網(wǎng)站,搜索strchr,即可轉(zhuǎn)到函數(shù)定義

79d4df00-25db-11ed-ba43-dac502259ad0.png

可以看到,該函數(shù)的作用是定位字符串中第一次出現(xiàn)該字符的位置,返回值是一個pointer指針

和我們猜想的一樣,它的作用就是在字符串中查找一個字符,并返回它第一次出現(xiàn)的位置的地址。

這樣一來,strchr函數(shù)的時間復(fù)雜度就很清楚了,就是遍歷字符串所需要的次數(shù),O(N)

NO.5 冒泡排序

voidBubbleSort(int*a,intn){     assert(a);     for (size_t end = n; end > 0; --end)     {         int exchange = 0;         for (size_t i = 1; i < end; ++i)         {          if (a[i-1] > a[i])          {                Swap(&a[i-1], &a[i]);                exchange = 1;          }       }     if (exchange == 0)       break;     }}

冒泡排序是一個非常經(jīng)典的代碼,其思路就是遍歷整個數(shù)組,如果待排序數(shù)字大于它的下一位,則交換這兩個數(shù)字

N個數(shù)字的數(shù)組需要N-1次排序才能完成

每一次排序都需要遍歷一次數(shù)組

這樣算來,冒泡排序的循環(huán)次數(shù)就是兩個N,即為O(N2)

能否通過循環(huán)層級判斷?

細心的你可能會發(fā)現(xiàn),上述代碼中出現(xiàn)了兩層循環(huán),那是不是可以通過循環(huán)層級來判斷時間復(fù)雜度呢?

并不能!

for(int i=0;i{  for(int j=0;j<3;j++)    printf("hehe
");}

如果是上述這種兩次循環(huán)的情況,會打印3n次呵呵,其時間復(fù)雜度是O(N)而不是N2

我們要準確分析算法的思路,并不能簡單地通過循環(huán)層級來判斷時間復(fù)雜度

NO.6 二分查找

intBinarySearch(int*a,intn,intx){assert(a);intbegin=0;intend=n-1;while(beginend){intmid=begin+((end-begin)>>1);//使用位移操作符來模擬/2,防止beginend相加后超出int范圍if(a[mid]begin=mid+1;elseif(a[mid]>x)end=mid;elsereturnmid;}return-1;}

二分查找的思路這里不再贅述

假設(shè)我們找了x次,每一次查找都會使查找范圍減半

N/2/2/2/2 ……

最后我們可以得出2條公式

2 x = N 2^x=N 2x=N

x = l o g 2 N x=log_2N x=log2N

最好情況:O(1)

最壞情況:O(logN)

79e08bac-25db-11ed-ba43-dac502259ad0.png

通過時間復(fù)雜度的對比,我們就能看出二分查找的優(yōu)勢在那里了

7a15a288-25db-11ed-ba43-dac502259ad0.png

可以看到,當數(shù)據(jù)很大的時候,O(logN)的算法執(zhí)行次數(shù)比O(N)少了特別多!!(來自BT-7274的肯定)

NO.7 計算N!

// 計算階乘遞歸Fac的時間復(fù)雜度?long long Fac(size_t N){     if(0 == N)      return 1;
     return Fac(N-1)*N;}

對于這個階乘的遞歸函數(shù)而言,每次函數(shù)調(diào)用是O(1),時間復(fù)雜度主要看遞歸次數(shù)

對于數(shù)字N而言,遞歸需要N次,時間復(fù)雜度是O(N)

遞歸算法時間復(fù)雜度計算

如果每次函數(shù)調(diào)用是O(1),看遞歸次數(shù)

每次函數(shù)調(diào)用不是O(1),那么就看他遞歸調(diào)用中次數(shù)的累加

NO.8 斐波那契數(shù)列

// 計算斐波那契遞歸Fib的時間復(fù)雜度?long long Fib(size_t N){     if(N < 3)      return 1;
     return Fib(N-1) + Fib(N-2);}

7a6d0c94-25db-11ed-ba43-dac502259ad0.png

每次遞歸,次數(shù)都會增加,總的來說是以2^x的量級增加的(x代表行數(shù))

1 + 2 + 4 + 8 + … … + 2 X ? 2 1+2+4+8+……+2^{X-2} 1+2+4+8+……+2X?2

這里一共有x-1項,用等比數(shù)列的求和公式得出,結(jié)果為2x-1

所以最后得出的時間復(fù)雜度為O(2N)

需要注意的是,當遞歸調(diào)用到底部時,有一些調(diào)用會較早退出,這部分位于金字塔的右下角

7a94b848-25db-11ed-ba43-dac502259ad0.png

由于時間復(fù)雜度只是一個估算值,這一部分缺失的調(diào)用次數(shù)對總運行次數(shù)的影響不大,故忽略掉

NO.9

void fun(int n) {   int i=l;   while(i<=n)      i=i*2;}

此函數(shù)有一個循環(huán),但是循環(huán)沒有被執(zhí)行n次,i每次都是2倍進行遞增,所以循環(huán)只會被執(zhí)行l(wèi)og2n次

NO.10

給定一個整數(shù)sum,從有N個有序元素的數(shù)組中尋找元素a,b,使得a+b的結(jié)果最接近sum,最快的平均時間復(fù)雜度是?

A. O(n)//√B. O(n^2)C. O(nlogn)D. O(logn)

數(shù)組元素有序,所以a,b兩個數(shù)可以分別從開始和結(jié)尾處開始搜,根據(jù)首尾元素的和是否大于sum,決定搜索的移動,整個數(shù)組被搜索一遍,就可以得到結(jié)果,所以最好時間復(fù)雜度為n

審核編輯:湯梓紅


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 算法
    +關(guān)注

    關(guān)注

    23

    文章

    4612

    瀏覽量

    92909
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4331

    瀏覽量

    62629
  • 復(fù)雜度
    +關(guān)注

    關(guān)注

    0

    文章

    8

    瀏覽量

    7907

原文標題:【算法】幾分鐘時間讓你徹底學(xué)會—時間復(fù)雜度!

文章出處:【微信號:cyuyanxuexi,微信公眾號:C語言編程學(xué)習(xí)基地】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    時間復(fù)雜度為 O(n^2) 的排序算法

    作者:京東保險 王奕龍 對于小規(guī)模數(shù)據(jù),我們可以選用時間復(fù)雜度為 O(n2) 的排序算法。因為時間復(fù)雜度并不代表實際代碼的執(zhí)行時間,它省去了
    的頭像 發(fā)表于 10-19 16:31 ?1161次閱讀
    <b class='flag-5'>時間</b><b class='flag-5'>復(fù)雜度</b>為 O(n^2) 的排序算法

    PCB與PCBA工藝復(fù)雜度的量化評估與應(yīng)用初探!

    , 不知道如何區(qū)分普通和復(fù)雜的PCB和 PCBA的設(shè)計,并采用什么樣的方式來處理。 基于上述考慮, 我們參考了業(yè) 界已有的作法, 設(shè)計了個PCB 和 PCBA的工藝復(fù)雜度計算公式以解決這 方面
    發(fā)表于 06-14 11:15

    JEM軟件復(fù)雜度的增加情況

    這篇文檔展示了幾個機構(gòu)關(guān)于JEM軟件復(fù)雜度的增加情況的看法,特別提出來創(chuàng)立個新的Ad-hoc組,研究降低軟件般性復(fù)雜度的可能方法。
    發(fā)表于 07-19 08:25

    時間復(fù)雜度是指什么

    原理->微機原理->軟件工程,編譯原理,數(shù)據(jù)庫數(shù)據(jù)結(jié)構(gòu)1.時間復(fù)雜度時間復(fù)雜度是指執(zhí)行算法所需要的計算工作量,因為整個算法的執(zhí)行時間與基本操
    發(fā)表于 07-22 10:01

    各種排序算法的時間空間復(fù)雜度、穩(wěn)定性

    各種排序算法的時間空間復(fù)雜度、穩(wěn)定性、排序算法分類:二、排序算法比較:注:1、歸并排序可以通過手搖算法將空間復(fù)雜度降到O(1),但是時間
    發(fā)表于 12-21 07:48

    圖像復(fù)雜度對信息隱藏性能影響分析

    針對信息隱藏中載體圖像的差異性,提出種圖像復(fù)雜度評價方法,綜合考慮圖像的壓縮特性以及圖像紋理能量作為圖像復(fù)雜度指標,并基于閾值劃分準則對栽體圖像進行復(fù)雜度分類,以幾種經(jīng)典的基于直方圖
    發(fā)表于 11-14 09:57 ?5次下載

    深度剖析時間復(fù)雜度

    相信每位錄友都接觸過時間復(fù)雜度,但又對時間復(fù)雜度的認識處于種朦朧的狀態(tài),所以是時候?qū)?/div>
    的頭像 發(fā)表于 03-18 10:18 ?1892次閱讀

    如何求遞歸算法的時間復(fù)雜度

    那么我通過道簡單的面試題,模擬面試的場景,來帶大家逐步分析遞歸算法的時間復(fù)雜度,最后找出最優(yōu)解,來看看同樣是遞歸,怎么就寫成了O(n)的代碼。
    的頭像 發(fā)表于 07-13 11:30 ?2267次閱讀

    如何求遞歸算法的時間復(fù)雜度

    相信很多同學(xué)對遞歸算法的時間復(fù)雜度都很模糊,那么這篇Carl來給大家通透的講講。
    的頭像 發(fā)表于 07-13 11:33 ?1617次閱讀

    算法之空間復(fù)雜度

    算法之空間復(fù)雜度:衡量個算法運行需要開辟的額外空間
    的頭像 發(fā)表于 08-31 10:29 ?1610次閱讀

    常見機器學(xué)習(xí)算法的計算復(fù)雜度

    時間復(fù)雜度不是測量個算法或段代碼在某個機器或者條件下運行所花費的時間。時間
    發(fā)表于 10-02 12:45 ?816次閱讀

    算法時空復(fù)雜度分析實用指南1

    我以前的文章主要都是講解算法的原理和解題的思維,對時間復(fù)雜度和空間復(fù)雜度的分析經(jīng)常筆帶過,主要是基于以下兩個原因:
    的頭像 發(fā)表于 04-12 14:37 ?520次閱讀
    算法時空<b class='flag-5'>復(fù)雜度</b>分析實用指南1

    算法時空復(fù)雜度分析實用指南2

    類似的,想想之前說的數(shù)據(jù)結(jié)構(gòu)擴容的場景,也許`N`次操作中的某次操作恰好觸發(fā)了擴容,導(dǎo)致時間復(fù)雜度提高,但總的時間復(fù)雜度依然保持在`O(N
    的頭像 發(fā)表于 04-12 14:38 ?536次閱讀
    算法時空<b class='flag-5'>復(fù)雜度</b>分析實用指南2

    算法時空復(fù)雜度分析實用指南(上)

    本文會篇幅較長,會涵蓋如下幾點: 1、Big O 表示法的幾個基本特點。 2、非遞歸算法中的時間復(fù)雜度分析。 3、數(shù)據(jù)結(jié)構(gòu) API 的效率衡量方法(攤還分析)。 4、遞歸算法的時間/空間
    的頭像 發(fā)表于 04-19 10:34 ?835次閱讀
    算法時空<b class='flag-5'>復(fù)雜度</b>分析實用指南(上)

    如何計算時間復(fù)雜度

    1 算法與時間復(fù)雜度 算法(Algorithm)是求解個問題需要遵循的,被清楚指定的簡單指令的集合。 算法旦確定,那么下步就要確定該算
    的頭像 發(fā)表于 10-13 11:19 ?2993次閱讀
    如何計算<b class='flag-5'>時間</b><b class='flag-5'>復(fù)雜度</b>