算法的基本概念
算法:對特定問題求解步驟的一種描述,它是指令的有限序列,其中的每條指令表示一個或多個操作。
根據以上定義,可以知道,算法一定是可以解決特定問題的,其次,它是有限的,然后,每一個指令都表示特定的操作。於是可以知道算法的五個特性:
- 有窮性:一個算法必須在執行有窮步之后結束,且每一步都必須在有窮時間內完成。如果有類似無限循環的語句,那么就不能稱之為算法。
- 可行性:一個算法是可行的,即算法中描述的操作都是可以通過已經實現的基本運算執行有限次來實現的。每一步操作都是可以實現的才能稱之為算法。
- 確定性:算法中每條指令、每條語句必須有確切的含義,相同的輸入必須得出到相同的輸出,不能產生二義性。
- 輸入:一個算法必須有零個或多個輸入。
- 輸出:一個算法必須有一個或多個輸出。
算法為什么是有窮的?在操作系統中使用了很多無窮的代碼語句,它們也是非常有用的,它們不是算法,那它們又是什么?對此,引入一個程序的概念,什么是算法,什么又是程序
根據上面的算法的定義,可以知道,算法是解決問題的一種方法或一個過程,例如如何將輸入轉換成輸出。一個問題可以有很多不同的算法。而程序是某種程序設計語言對算法的具體實現。我們可以用 C 語言來編寫,也可以用 Python 語言來編寫,只要是在計算機內部運行的程序設計語言都可以。這是對算法和程序的簡單描述。我們發現,算法更像一個解決問題的 “指導者”,而程序更像一個具體實現的 “實施者”,可以利用算法來指導程序的編寫和實施。
算法和程序主要有三方面的區別:
- 有窮性:算法必須是有窮的,程序可以是無窮的,所以在操作系統中,那些很有用的,但又無限循環的,可以 稱之為程序。
- 正確性:算法必須是正確的,程序可以是錯誤的。設計出的算法必須正確的來解決問題,而程序可以編寫錯誤然后進行修改。
- 描述方法:算法可以用偽代碼、程序語言、自然語言、程序框圖等描述,程序只能用程序設計語言編寫並可以運行。
算法效率的度量
如何設計一個 "好" 的算法?
首先一個好的算法必須具有正確性,應該能夠正確的解決問題。算法是一個 “指揮者”,如果一個 “指揮者” 不能正確的指導 “實施者” 去實施,那么它一定不是一個好的算法。
第二個是可讀性。算法應具有良好的可讀性,以幫助人們理解。在人們修改閱讀算法時,人們應能夠快速的理解掌握該算法。
第三個是健壯性。健壯性是指在輸入非法數據時,算法能適應的做出反應或進行處理。
最后一個是效率與存儲量需求。效率是指算法執行時間,存儲量需求是指算法執行過程中所需最大存儲空間。這是最常用的用來考量一個好的算法的標准。也就是時間復雜度與空間復雜度。
時間復雜度
在學習時間復雜度之前,先掌握兩個概念:語句的頻度、T(n)
語句頻度:該條語句可能重復執行的次數
T(n)
:所有語句的頻度之和,其中 n 為問題的規模
int sum = 0;
for(int i=1; i<=n; i++)
sum += i;
第一句是初始化 sum
為 0,它的語句頻度是 1,因為它只被執行了一次。第二個是循環體中的語句 sum += i
,根據它的判斷條件,可以知道它執行了 n 次,所以該條語句的語句頻度是 n。那么該段代碼的語句頻度之和就是 T(n)=1+n
。
時間復雜度:記作 T(n) = O(f(n))
,其中 O 表示 T(n)
與 f(n)
在 n 趨向於正無窮時為同階無窮大,可以把 f(n)
理解為某一個數量級或者是當 n 趨於正無窮時的一種增長率。
根據同階無窮大的知識,可以知道:
所以說,它的 f(n)=n
,它的時間復雜度為 O(n)
。
時間復雜度有三種分類:最壞時間復雜度、最好時間復雜度、平均時間復雜度
int sum = 0;
if(n != 0)
for(int i=1; i<=n; i++)
sum += i;
這段代碼中,如果 n 不等於 0 ,它的 T(n) = 1 + n
,它的時間復雜度為 O(n)
,如果當 n 等於 0 ,它僅僅執行了第一條語句,也就是說它的 T(n) = 1
,則它的時間復雜度為 O(1)
。所以說在不同的判斷中,時間復雜度是不同的,所以有最壞和最好之分,平均時間復雜度就是在所有輸入的概率的情況下,求一個時間復雜度的期望值。
在分析一個算法時, 往往會使用最壞時間復雜度,這個是最具有實際意義的。
學習了時間復雜度的分類后,來看一下時間復雜度在運算上有怎樣的規則。
加法規則:當對兩個時間復雜度進行求和運算時,可以將較大數量級的代碼的時間復雜度作為它們的和,可以通過同階無窮大來進行驗證
乘法規則:兩個時間復雜度的乘積可以使它先對數量級進行乘積再求同階無窮大
通常采用基本運算頻度來分析算法時間復雜度,基本運算頻度也就是指最深層的循環語句的頻度。
int sum = 0;
for(int i=1; i<=n; i++)
sum += i;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; i++)
sum += i;
這段代碼中,第一句的語句頻度是 1,然后第三句循環執行 n 次,語句頻度是 n,第四句第五句是一個雙層循環,並且都是循環 n 次,因此它的語句頻度是 n2 ,所以這段代碼的 T(n) = 1 + n + n2 。根據加法規則,它的時間復雜度是 O(n2) 。它的最深層的循環語句的時間復雜度為 O(n2) ,采用基本運算頻度來分析算法時間復雜度,也可以得出它的時間復雜度是 O(n2) 。
常見時間復雜度
空間復雜度
算法的空間復雜度是指算法消耗的存儲空間,記作 S(n) = O(g(n))
,O 表示同階無窮大,g(n) 表示數量級,n 代表問題規模。
在計算算法空間復雜度時,要注意一點,就是什么是消耗的存儲空間,它是除本身所用的指令、常數、變量和輸入數據外的輔助空間。
算法原地工作時指算法所需輔助空間為常量,記作 O(1)