[英]Time complexity of iterative and recursive algorithms
我在理解算法的時間復雜性時遇到問題。
讓我們以第一個示例為例,采用此算法在二進制搜索樹中進行搜索:
def search_iteratively(key, node):
current_node = node
while current_node is not None:
if key == current_node.key:
return current_node
elif key < current_node.key:
current_node = current_node.left
else: # key > current_node.key:
current_node = current_node.right
return None
那么,該如何計算時間復雜度呢?
讓我們以這個遞歸算法為例:
int f(int a, int b)
{
if (a > 0)
return f(a − 1, b − 3);
else
return b;
}
所以,我相信這個算法的那段時間復雜度為O(一),因為最終狀態僅取決於a
參數。
如果我寫下來:
T(a, b) = O(1) where a <= 0
T(a, b) = T(a-1, b-3) where a > 0
T(a, b) =
T(a-1, b-3) =
T(a-1, b-3) + T(a-2, b-6) =
T(a-1, b-3) + T(a-2, b-6) + T(a-3, b-9)
那么,我怎么知道這是線性時間復雜度? 僅僅因為遞歸將在a小於1時結束?
最后:
至於樹型搜索算法的復雜性,請嘗試考慮每次迭代都會更改的內容。 提示:考慮樹中current_node的深度。
在這種特殊情況下,嘗試使用歸納法證明線性復雜度。 您知道T(0,x)將以一個調用結束,這將成為您的基礎。 嘗試證明T(n,x)將執行n個遞歸調用。
在二進制搜索樹中找到值的最壞情況下的時間復雜度是多少? 最壞的情況是您必須下降到最深的葉子。 通常, n
節點的二叉樹可以具有深度O(n)
。 (考慮到每個右孩子都是葉子而左孩子向下下降的情況。)但是,如果維護平衡的二叉搜索樹(例如紅黑樹) ,則可以保證高度為O(log n)
。 這是在紅黑樹中進行鍵查找操作的最壞情況下的運行時間。
您的函數f
定義為:
a > 0
f(a, b) = f(a − 1, b − 3)
f(a, b) = b
否則 我們可以通過歸納法證明a
,在評價f(a, b)
對任何非負值a
需要a
到呼叫f
。 在基本情況下,如果a == 0
,則f
僅被調用一次。 對於正a
,假設f(a - 1, b)
被稱為a - 1
次。 然后評估f(a, b)
需要a - 1 + 1
= a
對f
a
調用。 (順便說一下,我們可以觀察到f(a, b) = b - 3*a
並得出一個恆定時間的實現。)
每個遞歸算法都可以轉換為迭代算法,該算法模擬在其上執行遞歸函數調用的堆棧。 觀察計算機執行迭代以實現您的遞歸程序。 更深刻地講,圖靈機是迭代的。 計算機科學的一個公理是,可以使用圖靈機來計算所有可以計算的東西。 拉姆達演算沒有比圖靈機提供更大的計算能力。
遞歸算法通常比迭代算法占用更多的時間和空間,因為它們需要為每個函數調用在堆棧上分配新的幀。
如果以每個函數調用都位於尾部位置的方式編寫遞歸函數,這意味着該調用不會返回需要進一步計算的中間值,則它是尾部遞歸函數。 遞歸計算不依賴於遞歸調用的參數以外的任何值。 因此,對函數的最終調用會立即產生最終結果,而無需返回遞歸調用鏈。
編譯器可以以重新使用當前幀的方式實現尾遞歸,而不必在堆棧上分配新的幀。 例如,需要方案編譯器來執行此操作。 所得的計算具有迭代的性能特征,但是代碼具有遞歸的表達優勢。
二叉樹算法最多訪問樹中的每個節點一次; 否則,二叉樹中會有一個循環,這是一個矛盾。 此外,在最壞的情況下,它至少會訪問每個節點一次。 因此,對節點的訪問次數為Theta(n),並且由於每次訪問都需要Theta(1)時間,因此最壞的運行時間為Theta(n)。
我們“知道”遞歸解決方案的方式是歸納證明。 您的情況是
任何b的T(0,b)= c
對於任何b,歸納假設為T(n,b)<= c(n + 1)。
歸納步驟是
T(n,b)<= c + T(n-1,b-3)<= c + cn = c(n + 1)。
因此,T(n)= O(n)。
不,遞歸算法不一定較慢,是的,可以用尾遞歸代替循環。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.