2.空間複雜度
學習資料結構和演算法,並不是為了死記硬背幾個知識點。我們的目的是建立時間複雜度、空間複雜度意識,寫出高質量的**,能夠設計基礎架構,提公升程式設計技能,訓練邏輯思維,積攢人生經驗,以此獲得工作回報,實現你的價值,完善你的人生。
掌握了資料結構與演算法,你看待問題的深度,解決問題的角度就會完全不一樣。因為這樣的你,就像是站在巨人的肩膀上,拿著生存利器行走世界。資料結構與演算法,會為你的程式設計之路,甚至人生之路開啟一扇通往新世界的大門。
對資料結構和演算法,要學習它的來歷、自身的特點、適合解決的問題和實際的應用場景。
最常用的、最基礎資料結構與演算法:
10 個資料結構:陣列、鍊錶、棧、佇列、雜湊表、二叉樹、堆、跳表、圖、trie 樹;
10 個演算法:遞迴、排序、二分查詢、搜尋、雜湊演算法、貪心演算法、分治演算法、回溯演算法、動態規劃、字串匹配演算法。
我們需要乙個不用具體測試就可以粗略地估計演算法的執行效率的方法。這就是時間、空間複雜度分析方法,即大 o 複雜度表示法。
所有**的執行時間 t(n) 與每行**的執行次數 n 成正比,因此我們用t(n) = o(f(n))
來表示**執行時間,即大 o 時間複雜度表示法。
大o 時間複雜度實際上並不具體表示**真正的執行時間,而是表示**執行時間隨資料規模增長的變化趨勢。n 很大時,你可以把它想象成 10000、100000。而公式中的低階、常量、係數三部分並不左右增長趨勢,所以都可以忽略。我們只需要記錄乙個最大量級就可以了。
只關注迴圈執行次數最多的一段**
int
cal(
int n)
return sum;
}
其中第 2、3 行**都是常量級的執行時間,與 n 的大小無關,所以對於複雜度並沒有影響。迴圈執行次數最多的是第 4、5 行**,所以這塊**要重點分析。前面我們也講過,這兩行**被執行了 n 次,所以總的時間複雜度就是 o(n)。
總複雜度等於量級最大的那段**的複雜度
int
cal(
int n)
int sum_2 =0;
int q =1;
for(
; q < n;
++q)
int sum_3 =0;
int i =1;
int j =1;
for(
; i <= n;
++i)
}return sum_1 + sum_2 + sum_3;
}
這個**分為三部分,分別是求 sum_1、sum_2、sum_3。我們可以分別分析每一部分的時間複雜度,然後把它們放到一塊兒,再取乙個量級最大的作為整段**的複雜度。
第一段的時間複雜度是多少呢?這段**迴圈執行了 100 次,所以是乙個常量的執行時間,跟 n 的規模無關。這裡再強調一下,即便這段**迴圈 10000 次、100000 次,只要是乙個已知的數,跟 n 無關,照樣也是常量級的執行時間。當 n 無限大的時候,就可以忽略。儘管對**的執行時間會有很大影響,但是回到時間複雜度的概念來說,它表示的是乙個演算法執行效率與資料規模增長的變化趨勢,所以不管常量的執行時間多大,我們都可以忽略掉。因為它本身對增長趨勢並沒有影響。
那第二段**和第三段**的時間複雜度是 o(n) 和 o(n2)。綜合這三段**的時間複雜度,我們取其中最大的量級。所以整段**的時間複雜度就為 o(n2)。也就是說:總的時間複雜度就等於量級最大的那段**的時間複雜度 。
巢狀**的複雜度等於巢狀內外**複雜度的乘積
int
cal(
int n)
}intf(
int n)
return sum;
}
我們單獨看 cal() 函式。假設 f() 只是乙個普通的操作,那第 4~6 行的時間複雜度就是t1(n) = o(n)。但 f() 函式本身不是乙個簡單的操作,它的時間複雜度是 t2(n) = o(n),所以,整個 cal() 函式的時間複雜度就是,t(n) = t1(n) * t2(n) = o(n*n) = o(n2)。
常量級 o(1)
只要**的執行時間不隨 n 的增大而增長,這樣**的時間複雜度我們都記作 o(1)。或者說一般情況下,只要演算法中不存在迴圈語句、遞迴語句,即使有成千上萬行的**,其時間複雜度也是ο(1)。
對數階 o(logn)
對數階時間複雜度非常常見,同時也是最難分析的一種時間複雜度。
i=1;
while
(i <= n)
其實相當於求解 2x=n 中 x的值, 也就是x=log2n,所以這段**的時間複雜度就是 o(log2n)。
i=1;
while
(i <= n)
很簡單就能看出來,這段**的時間複雜度為 o(log3n)。實際上,不管是以 2 為底、以 3 為底,還是以 10 為底,我們可以把所有對數階的時間複雜度都記為 o(logn)。為什麼呢?我們知道,對數之間是可以互相轉換的,log3n 就等於 log32 * log2n,所以 o(log3n) = o(c * log2n),其中 c=log32 是乙個常量。基於我們前面的乙個理論:在採用大 o 標記複雜度的時候,可以忽略係數,即 o(cf(n)) = o(f(n))。所以,o(log2n) 就等於 o(log3n)。因此,在對數階時間複雜度的表示方法裡,我們忽略對數的「底」,統一表示為 o(logn)。
o(n)
o(nlogn)
像快排的時間複雜度就是o(nlogn)。
public
static
void
quicksort
(int
arr,
int left,
int right)
int temp;
int i = left;
int j = right;
int basenum = arr[left]
;//開始迴圈尋找
while
(i != j)
while
(i < j && arr[i]
<= basenum)
//此時說明停下來,交換兩個數字置
temp = arr[i]
; arr[i]
= arr[j]
; arr[j]
= temp;
}//跳出while迴圈說明兩個指標相遇,此時基準數歸位
arr[left]
= arr[i]
; arr[i]
= basenum;
//繼續遞迴呼叫
quicksort
(arr, left, i -1)
;quicksort
(arr, i +
1, right)
;}
n2、n3、nk等k次方階
指數階o(2n) 、 階乘階o(n!)
這兩個屬於非多項式量級,我們把時間複雜度為非多項式量級的演算法問題叫作 np(non-deterministic polynomial,非確定多項式)問題。非多項式時間複雜度的演算法其實是非常低效的演算法,一般很少遇到。
o(m+n)、o(m*n)
從下面**中可以看出,m 和 n 是表示兩個資料規模。我們無法事先評估 m 和 n 誰的量級大,所以我們在表示複雜度的時候,就不能簡單地利用加法法則,省略掉其中乙個。所以下面**的時間複雜度就是 o(m+n)。
int
cal(
int m,
int n)
int sum_2 =0;
int j =1;
for(
; j < n;
++j)
return sum_1 + sum_2;
}
顧名思義,最好情況時間複雜度就是,在最理想的情況下,執行這段**的時間複雜度。同理,最壞情況時間複雜度就是,在最糟糕的情況下,執行這段**的時間複雜度。
而平均時間複雜度實際上在概率論中,應該叫加權平均時間複雜度或者期望時間複雜度。很多時候,我們使用乙個複雜度就可以滿足需求了。只有同一塊**在不同的情況下,時間複雜度有量級的差距,我們才會使用這三種複雜度表示法來區分。
均攤時間複雜度,對乙個資料結構進行一組連續操作中,大部分情況下時間複雜度都很低,只有個別情況下時間複雜度比較高,而且這些操作之間存在前後連貫的時序關係,這個時候,我們就可以將這一組操作放在一塊兒分析,看是否能將較高時間複雜度那次操作的耗時平攤到其他那些時間複雜度比較低的操作上。而且,在能夠應用均攤時間複雜度分析的場合,一般均攤時間複雜度就等於最好情況時間複雜度。
表示演算法的儲存空間與資料規模之間的增長關係
void
print
(int n)
for(i = n-
1; i >=0;
--i)
}
跟時間複雜度分析一樣,我們可以看到第 2 行**中,我們申請了乙個空間儲存變數 i,但是它是常量階的,跟資料規模 n 沒有關係,所以我們可以忽略。第 3 行申請了乙個大小為 n 的 int 型別陣列,除此之外,剩下的**都沒有占用更多的空間,所以整段**的空間複雜度就是 o(n)。
我們常見的空間複雜度就是 o(1)、o(n)、o(n2),像 o(logn)、o(nlogn) 這樣的對數階複雜度平時都用不到。
資料結構之時間複雜度和空間複雜度
演算法複雜度分為時間複雜度和空間複雜度,乙個好的演算法應該具體執行時間短,所需空間少的特點。隨著計算機硬體和軟體的提公升,乙個演算法的執行時間是算不太精確的。只能依據統計方法對演算法進行估算。我們拋開硬體和軟體的因素,演算法的好壞直接影響程式的執行時間。我們看一下小例子 int value 0 執行...
資料結構之時間複雜度和空間複雜度
準備系統性的記錄一下資料結構與演算法的知識點,今天就先從時間複雜度與空間複雜度開始咯 時間複雜度的定義 在電腦科學中,演算法的時間複雜度是乙個函式,它定量描述了該演算法的執行時間。乙個演算法執行所耗費的時間,從理論上說,是不能算出來的,只有你把你的程式放在機器上跑起來,才能知道。並且在測試過程中還需...
資料結構與演算法之時間複雜度
一般情況下,演算法中的基本操作語句的重複執行次數是問題規模n的某個函式,用t n 表示,若有某個輔助函式f n 使得當n趨近於無窮大時,t n f n 的極限值為不等於零的常數,則稱f n 是t n 的同數量級函式。記作 t n f n 稱 f n 為演算法的漸進時間複雜度,簡稱時間複雜度。t n ...