大O符號初學者指南
原文地址:https://rob-bell.net/2009/06/a-beginners-guide-to-big-o-notation/
計算機科學中,大O表示法被用來描述一個算法的性能或復雜度。大O表示法可以用來描述一個算法的最差情況,或者一個算法執行的耗時或占用空間(例如內存或磁盤占用)。
相信許多人讀過《Programming Pearls》(《編程珠璣》)或者其他計算機科學書籍時,在看到大O符號或者其他奇怪的語法符號時都會感覺到自己遇到了一堵無法翻越的高墻。那這篇文章將會帶領大家對大O表示法以及對數級算法有一個最簡單的認識。
首先作為一個程序員,其次作為一個數學家,我(Rob Bell)發現透徹的理解大O表示法的最好方式就是來嘗試一些代碼示例。下面按照算法的增長級別,展示了一些常見的算法描述,同時針對每個算法給出了一個簡單的示例。
O(1)
O(1)表示該算法的執行時間(或執行時占用空間)總是為一個常量,不論輸入的數據集是大是小。
bool IsFirstElementNull(IList<string> elements)
{
return elements[0] == null;
}
O(N)
O(N)表示一個算法的性能會隨著輸入數據的大小變化而線性變化。下面的例子同時也表明了大O表示法其實是用來描述一個算法的最差情況的:在for循環中,一旦程序找到了輸入數據中與第二個傳入的string匹配時,程序就會提前退出,然而大O表示法卻總是假定程序會運行到最差情況(在這個例子中,意味著大O會表示程序全部循環完成時的性能)。
bool ContainsValue(IList<string> elements, string value)
{
foreach (var element in elements)
{
if (element == value) return true;
}
return false;
}
O(N^2)
O(N^2)表示一個算法的性能將會隨著輸入數據的增長而呈現出二次增長。最常見的算法就是對輸入數據進行嵌套循環。如果嵌套層級不斷深入的話,算法的性能將會變為O(N3),O(N4),以此類推。
bool ContainsDuplicates(IList<string> elements)
{
for (var outer = 0; outer < elements.Count; outer++)
{
for (var inner = 0; inner < elements.Count; inner++)
{
// Don‘t compare with self
if (outer == inner) continue;
if (elements[outer] == elements[inner]) return true;
}
}
return false;
}
O(2^N)
O(2^N)表示一個算法的性能將會隨著輸入數據的每次增加而增大兩倍。O(2^N)的增長曲線是一條爆炸式增長曲線——開始時較為平滑,但數據增長後曲線增長非常陡峭。一個典型的O(2^N)方法就是裴波那契數列的遞歸計算實現。
int Fibonacci(int number)
{
if (number <= 1) return number;
return Fibonacci(number - 2) + Fibonacci(number - 1);
}
對數
要說明對數情況,稍稍有點復雜,因此我將使用一個非常通用的示例:
二分查找是一種用來在有序集合中進行查找的高效算法。二分查找從數據集的中間位置開始,然後用這個中間值和一個目標值進行比較。如果比較結果為相等,則程序返回成功。如果目標值大於中間值,程序會截取從中間值開始到最大值的那段數據集,並重復執行同樣的查找方法。想死的,如果目標值小於中間值,程序將會繼續在數據集中較小的那一半執行二分查找。二分查找程序會持續的將數據集對等分,以進入下一次循環,直到最終找到與目標值相等的數據後,程序就退出。
這類算法的性能就會被描述為O(logN)。正是通過這種不斷對數據進行對等分的二分查找操作,使得二分查找算法的曲線從一個峰值開始,隨著輸入數據集的增長而慢慢的變得平緩。用例子來說明的話,例如一個包含10個輸入數據的程序需要耗時一秒完成,則一個包含100個輸入數據的程序就需要耗時兩秒,然後一個包含1000個輸入數據的程序就耗時三秒。加倍的輸入數據對這類算法的性能結果影響非常小。基於如此,類似於二分查找的對數級算法在處理大量數據集時非常高效。
本文僅僅覆蓋了關於大O表示法以及對數算法非常基本的知識概念。如果想要更深入的理解他們,可以參考維基百科:
大O表示法:https://en.wikipedia.org/wiki/Big_O_notation
對數:https://en.wikipedia.org/wiki/Logarithm
大O符號初學者指南