簡體   English   中英

迭代和遞歸算法的時間復雜度

[英]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 = af 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM