簡體   English   中英

python中一個類中的遞歸

[英]Recursion within a class in python

我知道這是一個非常基本的問題,我在網上找到了示例代碼,但我無法弄清楚它的工作原理。

如果我們需要以預購方式遍歷二叉樹,其中一種方法(在此處引用http://interactivepython.org/courselib/static/pythonds/Trees/TreeTraversals.html )是通過使用類似的東西:

def preorder(self):
     print(self.key)
     if self.leftChild:
        self.leftChild.preorder()
     if self.rightChild:
        self.rightChild.preorder()

我不明白為什么做self.leftChild.preorder()這樣的事情是可能的。 如果有人能指出我正確的方向,我將非常感激。

編輯:

正如評論中所建議的那樣,我發布了我正在處理的完整代碼。 我從firecode得到它:

post_ordered_list = []
class BinaryTree:

    def __init__(self, root_data):
        self.data = root_data
        self.left_child = None
        self.right_child = None

    def postorder(self):
        if self.left_child:
            self.left_child.postorder()
        if self.right_child:
            self.right_child.postorder()
        post_ordered_list.append(self.data)
        return post_ordered_list


    def get_right_child(self):
        return self.right_child

    def get_left_child(self):
        return self.left_child

    def set_root_val(self, obj):
        self.data = obj

    def get_root_val(self):
        return self.data

在開始編程時,遞歸是很難掌握的。 你需要意識到的一件事是,如果你正確設置了基本情況(例如,如果是self.left,如果是self.right等),你可以使用你正在處理的函數,就好像它是已經工作了。

讓我們考慮使用函數countNodes()計算樹中所有節點的示例:假設我們的節點x位於樹中的某個位置。 當調用x來計算其子樹的所有節點時,它是如何做到的? 還記得我怎么說我們必須假裝函數countNodes()存在並且它已經有效了嗎? 好吧,讓我們做到這一點。 X需要自我計數,因為它是一個節點。 因此到目前為止計數為1。 在計算自己之后,它必須計算左邊的所有節點和右邊的所有節點。 因此,要計算從任何節點x開始的樹中的節點,我們調用left的countNodes()和右邊的countNodes()。

所以代碼看起來像這樣:

def countNodes(self):
    count = 1
    if self.left: #Checking to see if we have a left subtree
        count += countNodes(self.left)
    if self.right: #Checking to see if we have a right subtree
        count += countNodes(self.right)
    return count

所以現在我們更好地理解了遞歸,讓我們回到你的例子。 我們希望以預購方式遍歷樹。 因此,根據定義,這意味着我們必須首先訪問我們的節點。 然后我們看看我們是否有一個要訪問的左節點。 如果是這樣,我們以預訂方式遍歷左節點。 如果我們有一個正確的節點,我們也會以預訂方式遍歷整個樹。

遞歸的最大收獲:

  1. 確保你有良好的基本情況(例如,如果node.right == null)

  2. 找到重復的模式。 只要您具有正確工作的基本案例,就可以在函數中使用該函數,就像它已經構建一樣。

我希望有所幫助!

編輯:

解釋我沒有回答的自我部分。 Self表示任何稱為方法的對象。 因此,如果我們有一個節點x,我們想要進行前序遍歷,我們將使用x.preorder() 然后在函數中,它看起來像這樣:

def preorder(self): #self is whatever calls this function
    print(self.value) #whaver you want to print
    if self.left:
       self.left.preorder() #now in this function call, self will be self.left
   if self.right:
       self.right.preorder() #same idea here


root.preorder() #calling the function. Now self will be root.

我希望能為你解決一些問題。 對不起,首先不了解問題。 我希望這能解決它。 如果您有更多問題或需要更多說明,請與我們聯系。

遞歸有兩個步驟:基本案例和遞歸案例。 基本情況會停止遞歸,但是根據我對帖子的理解,您正在尋找遞歸案例的原因。 遞歸情況的關鍵是下一個遞歸小於調用它的遞歸。

您的預訂函數將root作為其參數。 第一次調用preorder時,您使用self作為參數,這意味着您正在接受整個樹。 如果root有一個左子,那么下一步是考慮左子樹。 左子樹的根是當前根的左子節點,因此它作為參數傳入。 只要有一個左孩子,你繼續向左遞減。 當沒有左子節點並且代碼繼續到該最后一個節點的右子if語句時,遞歸停止。

我可以繼續,但不是沒有混淆。 (希望我不會混淆!)在二元搜索上查看此頁面 ,這是一個非常類似的操作。

在Python中, classInstance.methodName(params...)相當於調用某個類的methodName方法,並將classInstance作為self傳遞:

  1. 確定哪個類是classInstance ,可以使用type(classInstance)classInstance.__class__ (查找classInstance = Class(...)實例化代碼)。
  2. 確定類是否將methodName定義為self作為第一個參數。 self是第一個參數表示它是一個實例方法,而不是類方法或靜態方法(請參閱下面的鏈接解釋)。 如果有這樣的方法,則使用selfclassInstance調用它,即等效的調用將是Class.methodName(classInstance, params...)
  3. 如果類沒有定義methodName ,那么在繼承文檔之后,查找最接近的祖先,並執行同樣的操作。 在這種情況下,等效調用看起來像: ParentClass.methodName(classInstnace, params...)

這是一個例子:

n4 = BinaryTree(4)
n5 = BinaryTree(5)
n3 = BinaryTree(3)
n3.left_child = n5
n3.right_child = n4
"""
  3
 /  \
4    5
"""

n3.postorder()
# result [5, 4, 3]

當調用n3.postorder()

  • selfn3
  • self.leftchildn5
  • self.rightchildn4

n3.postorder()被執行時,下一行是self.left_child.postorder()並調用postorder與方法self.leftchild (即n5的)作為第一個參數(即“自我”) postorder 因此,在這個遞歸調用的上下文中:

  • selfn5
  • self.leftchildNone
  • self.rightchildNone

然后該方法調用結束,下一行, self.right_child.postorder()執行,它與上面相同,但是使用n4 ,因為我們回到原始上下文中,其中self.right_childn4

有關深入文檔,請訪問: https//docs.python.org/3/tutorial/classes.html

實例,類和靜態方法之間的區別: https//julien.danjou.info/guide-python-static-class-abstract-methods/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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