[英]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
所以現在我們更好地理解了遞歸,讓我們回到你的例子。 我們希望以預購方式遍歷樹。 因此,根據定義,這意味着我們必須首先訪問我們的節點。 然后我們看看我們是否有一個要訪問的左節點。 如果是這樣,我們以預訂方式遍歷左節點。 如果我們有一個正確的節點,我們也會以預訂方式遍歷整個樹。
遞歸的最大收獲:
確保你有良好的基本情況(例如,如果node.right == null)
找到重復的模式。 只要您具有正確工作的基本案例,就可以在函數中使用該函數,就像它已經構建一樣。
我希望有所幫助!
編輯:
解釋我沒有回答的自我部分。 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
傳遞:
classInstance
,可以使用type(classInstance)
或classInstance.__class__
(查找classInstance = Class(...)
實例化代碼)。 methodName
定義為self
作為第一個參數。 self
是第一個參數表示它是一個實例方法,而不是類方法或靜態方法(請參閱下面的鏈接解釋)。 如果有這樣的方法,則使用self
為classInstance
調用它,即等效的調用將是Class.methodName(classInstance, params...)
。 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()
self
是n3
self.leftchild
是n5
self.rightchild
是n4
。 當n3.postorder()
被執行時,下一行是self.left_child.postorder()
並調用postorder
與方法self.leftchild
(即n5
的)作為第一個參數(即“自我”) postorder
。 因此,在這個遞歸調用的上下文中:
self
是n5
self.leftchild
是None
self.rightchild
是None
。 然后該方法調用結束,下一行, self.right_child.postorder()
執行,它與上面相同,但是使用n4
,因為我們回到原始上下文中,其中self.right_child
是n4
。
有關深入文檔,請訪問: 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.