mirror of
https://github.com/krahets/hello-algo.git
synced 2025-07-24 10:14:44 +08:00
build
This commit is contained in:
22
zh-Hant/docs/chapter_computational_complexity/index.md
Normal file
22
zh-Hant/docs/chapter_computational_complexity/index.md
Normal file
@ -0,0 +1,22 @@
|
||||
---
|
||||
comments: true
|
||||
icon: material/timer-sand
|
||||
---
|
||||
|
||||
# 第 2 章 複雜度分析
|
||||
|
||||
{ class="cover-image" }
|
||||
|
||||
!!! abstract
|
||||
|
||||
複雜度分析猶如浩瀚的演算法宇宙中的時空嚮導。
|
||||
|
||||
它帶領我們在時間與空間這兩個維度上深入探索,尋找更優雅的解決方案。
|
||||
|
||||
## Chapter Contents
|
||||
|
||||
- [2.1 演算法效率評估](https://www.hello-algo.com/en/chapter_computational_complexity/performance_evaluation/)
|
||||
- [2.2 迭代與遞迴](https://www.hello-algo.com/en/chapter_computational_complexity/iteration_and_recursion/)
|
||||
- [2.3 時間複雜度](https://www.hello-algo.com/en/chapter_computational_complexity/time_complexity/)
|
||||
- [2.4 空間複雜度](https://www.hello-algo.com/en/chapter_computational_complexity/space_complexity/)
|
||||
- [2.5 小結](https://www.hello-algo.com/en/chapter_computational_complexity/summary/)
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,52 @@
|
||||
---
|
||||
comments: true
|
||||
---
|
||||
|
||||
# 2.1 演算法效率評估
|
||||
|
||||
在演算法設計中,我們先後追求以下兩個層面的目標。
|
||||
|
||||
1. **找到問題解法**:演算法需要在規定的輸入範圍內可靠地求得問題的正確解。
|
||||
2. **尋求最優解法**:同一個問題可能存在多種解法,我們希望找到儘可能高效的演算法。
|
||||
|
||||
也就是說,在能夠解決問題的前提下,演算法效率已成為衡量演算法優劣的主要評價指標,它包括以下兩個維度。
|
||||
|
||||
- **時間效率**:演算法執行速度的快慢。
|
||||
- **空間效率**:演算法佔用記憶體空間的大小。
|
||||
|
||||
簡而言之,**我們的目標是設計“既快又省”的資料結構與演算法**。而有效地評估演算法效率至關重要,因為只有這樣,我們才能將各種演算法進行對比,進而指導演算法設計與最佳化過程。
|
||||
|
||||
效率評估方法主要分為兩種:實際測試、理論估算。
|
||||
|
||||
## 2.1.1 實際測試
|
||||
|
||||
假設我們現在有演算法 `A` 和演算法 `B` ,它們都能解決同一問題,現在需要對比這兩個演算法的效率。最直接的方法是找一臺計算機,執行這兩個演算法,並監控記錄它們的執行時間和記憶體佔用情況。這種評估方式能夠反映真實情況,但也存在較大的侷限性。
|
||||
|
||||
一方面,**難以排除測試環境的干擾因素**。硬體配置會影響演算法的效能。比如在某臺計算機中,演算法 `A` 的執行時間比演算法 `B` 短;但在另一臺配置不同的計算機中,可能得到相反的測試結果。這意味著我們需要在各種機器上進行測試,統計平均效率,而這是不現實的。
|
||||
|
||||
另一方面,**展開完整測試非常耗費資源**。隨著輸入資料量的變化,演算法會表現出不同的效率。例如,在輸入資料量較小時,演算法 `A` 的執行時間比演算法 `B` 短;而在輸入資料量較大時,測試結果可能恰恰相反。因此,為了得到有說服力的結論,我們需要測試各種規模的輸入資料,而這需要耗費大量的計算資源。
|
||||
|
||||
## 2.1.2 理論估算
|
||||
|
||||
由於實際測試具有較大的侷限性,因此我們可以考慮僅透過一些計算來評估演算法的效率。這種估算方法被稱為<u>漸近複雜度分析(asymptotic complexity analysis)</u>,簡稱<u>複雜度分析</u>。
|
||||
|
||||
複雜度分析能夠體現演算法執行所需的時間和空間資源與輸入資料大小之間的關係。**它描述了隨著輸入資料大小的增加,演算法執行所需時間和空間的增長趨勢**。這個定義有些拗口,我們可以將其分為三個重點來理解。
|
||||
|
||||
- “時間和空間資源”分別對應<u>時間複雜度(time complexity)</u>和<u>空間複雜度(space complexity)</u>。
|
||||
- “隨著輸入資料大小的增加”意味著複雜度反映了演算法執行效率與輸入資料體量之間的關係。
|
||||
- “時間和空間的增長趨勢”表示複雜度分析關注的不是執行時間或佔用空間的具體值,而是時間或空間增長的“快慢”。
|
||||
|
||||
**複雜度分析克服了實際測試方法的弊端**,體現在以下兩個方面。
|
||||
|
||||
- 它獨立於測試環境,分析結果適用於所有執行平臺。
|
||||
- 它可以體現不同資料量下的演算法效率,尤其是在大資料量下的演算法效能。
|
||||
|
||||
!!! tip
|
||||
|
||||
如果你仍對複雜度的概念感到困惑,無須擔心,我們會在後續章節中詳細介紹。
|
||||
|
||||
複雜度分析為我們提供了一把評估演算法效率的“標尺”,使我們可以衡量執行某個演算法所需的時間和空間資源,對比不同演算法之間的效率。
|
||||
|
||||
複雜度是個數學概念,對於初學者可能比較抽象,學習難度相對較高。從這個角度看,複雜度分析可能不太適合作為最先介紹的內容。然而,當我們討論某個資料結構或演算法的特點時,難以避免要分析其執行速度和空間使用情況。
|
||||
|
||||
綜上所述,建議你在深入學習資料結構與演算法之前,**先對複雜度分析建立初步的瞭解,以便能夠完成簡單演算法的複雜度分析**。
|
2384
zh-Hant/docs/chapter_computational_complexity/space_complexity.md
Executable file
2384
zh-Hant/docs/chapter_computational_complexity/space_complexity.md
Executable file
File diff suppressed because it is too large
Load Diff
53
zh-Hant/docs/chapter_computational_complexity/summary.md
Normal file
53
zh-Hant/docs/chapter_computational_complexity/summary.md
Normal file
@ -0,0 +1,53 @@
|
||||
---
|
||||
comments: true
|
||||
---
|
||||
|
||||
# 2.5 小結
|
||||
|
||||
### 1. 重點回顧
|
||||
|
||||
**演算法效率評估**
|
||||
|
||||
- 時間效率和空間效率是衡量演算法優劣的兩個主要評價指標。
|
||||
- 我們可以透過實際測試來評估演算法效率,但難以消除測試環境的影響,且會耗費大量計算資源。
|
||||
- 複雜度分析可以消除實際測試的弊端,分析結果適用於所有執行平臺,並且能夠揭示演算法在不同資料規模下的效率。
|
||||
|
||||
**時間複雜度**
|
||||
|
||||
- 時間複雜度用於衡量演算法執行時間隨資料量增長的趨勢,可以有效評估演算法效率,但在某些情況下可能失效,如在輸入的資料量較小或時間複雜度相同時,無法精確對比演算法效率的優劣。
|
||||
- 最差時間複雜度使用大 $O$ 符號表示,對應函式漸近上界,反映當 $n$ 趨向正無窮時,操作數量 $T(n)$ 的增長級別。
|
||||
- 推算時間複雜度分為兩步,首先統計操作數量,然後判斷漸近上界。
|
||||
- 常見時間複雜度從低到高排列有 $O(1)$、$O(\log n)$、$O(n)$、$O(n \log n)$、$O(n^2)$、$O(2^n)$ 和 $O(n!)$ 等。
|
||||
- 某些演算法的時間複雜度非固定,而是與輸入資料的分佈有關。時間複雜度分為最差、最佳、平均時間複雜度,最佳時間複雜度幾乎不用,因為輸入資料一般需要滿足嚴格條件才能達到最佳情況。
|
||||
- 平均時間複雜度反映演算法在隨機資料輸入下的執行效率,最接近實際應用中的演算法效能。計算平均時間複雜度需要統計輸入資料分佈以及綜合後的數學期望。
|
||||
|
||||
**空間複雜度**
|
||||
|
||||
- 空間複雜度的作用類似於時間複雜度,用於衡量演算法佔用記憶體空間隨資料量增長的趨勢。
|
||||
- 演算法執行過程中的相關記憶體空間可分為輸入空間、暫存空間、輸出空間。通常情況下,輸入空間不納入空間複雜度計算。暫存空間可分為暫存資料、堆疊幀空間和指令空間,其中堆疊幀空間通常僅在遞迴函式中影響空間複雜度。
|
||||
- 我們通常只關注最差空間複雜度,即統計演算法在最差輸入資料和最差執行時刻下的空間複雜度。
|
||||
- 常見空間複雜度從低到高排列有 $O(1)$、$O(\log n)$、$O(n)$、$O(n^2)$ 和 $O(2^n)$ 等。
|
||||
|
||||
### 2. Q & A
|
||||
|
||||
**Q**:尾遞迴的空間複雜度是 $O(1)$ 嗎?
|
||||
|
||||
理論上,尾遞迴函式的空間複雜度可以最佳化至 $O(1)$ 。不過絕大多數程式語言(例如 Java、Python、C++、Go、C# 等)不支持自動最佳化尾遞迴,因此通常認為空間複雜度是 $O(n)$ 。
|
||||
|
||||
**Q**:函式和方法這兩個術語的區別是什麼?
|
||||
|
||||
<u>函式(function)</u>可以被獨立執行,所有參數都以顯式傳遞。<u>方法(method)</u>與一個物件關聯,被隱式傳遞給呼叫它的物件,能夠對類別的例項中包含的資料進行操作。
|
||||
|
||||
下面以幾種常見的程式語言為例來說明。
|
||||
|
||||
- C 語言是程序式程式設計語言,沒有物件導向的概念,所以只有函式。但我們可以透過建立結構體(struct)來模擬物件導向程式設計,與結構體相關聯的函式就相當於其他程式語言中的方法。
|
||||
- Java 和 C# 是物件導向的程式語言,程式碼塊(方法)通常作為某個類別的一部分。靜態方法的行為類似於函式,因為它被繫結在類別上,不能訪問特定的例項變數。
|
||||
- C++ 和 Python 既支持程序式程式設計(函式),也支持物件導向程式設計(方法)。
|
||||
|
||||
**Q**:圖解“常見的空間複雜度型別”反映的是否是佔用空間的絕對大小?
|
||||
|
||||
不是,該圖展示的是空間複雜度,其反映的是增長趨勢,而不是佔用空間的絕對大小。
|
||||
|
||||
假設取 $n = 8$ ,你可能會發現每條曲線的值與函式對應不上。這是因為每條曲線都包含一個常數項,用於將取值範圍壓縮到一個視覺舒適的範圍內。
|
||||
|
||||
在實際中,因為我們通常不知道每個方法的“常數項”複雜度是多少,所以一般無法僅憑複雜度來選擇 $n = 8$ 之下的最優解法。但對於 $n = 8^5$ 就很好選了,這時增長趨勢已經佔主導了。
|
3950
zh-Hant/docs/chapter_computational_complexity/time_complexity.md
Executable file
3950
zh-Hant/docs/chapter_computational_complexity/time_complexity.md
Executable file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user