標籤:port create 非遞迴 先來 遞迴 elf style 鏈表 基礎
二叉樹是很重要的資料結構,在面試還是日常開發中都是很重要的角色。
首先是建立樹的過程,對比C或是C++的實現來講,其涉及到了較為複雜的指標操作,但是在物件導向的語言中,就不需要考慮指標, 記憶體等。首先我們需要定義一個樹節點, 我們採用基於鏈表設計的節點, 首先定義一個資料域, 其次就是左孩子和右孩子。如下定義:
# 樹節點的定義class Node: def __init__(self, data=-1, lchild=None, rchild=None): self.lchild = lchild # 表示左子樹 self.rchild = rchild # 表示右子樹 self.data = data # 表示資料域
建立樹的實現有兩種,遍曆建樹與層次建樹,這兩種分別是基於堆棧和隊列來實現的,先來看看最基本的遞迴建樹。
遞迴建樹的過程無非就是一路走到底,但是需要將節點的左右孩子節點對其餘的節點相關聯起來。因此,我們可以如此來實現:
def traversal_create(self, root):data = input()if data is "#":return Noneelse:root.data = dataroot.lchild = self.traversal_create(root.lchild)root.rchild = self.traversal_create(root.rchild)return root
首先我們傳入的參數是一個預設的節點,其data資料域為-1,然後我們接受輸入的資料,賦值給節點資料域,然後就是遞迴了,將左右孩子節點關聯起來。總體來講,應該不難理解。
下面看看層次建樹的實現,所謂層次建樹其實就是基於隊列的操作,利用隊列先進先出的特點,每次我們訪問一個節點的時候,將其存入隊列中,待遍曆玩當前節點的左右孩子節點,隊列就彈出一個節點,之後的操作都是一樣的。看看代碼:
def add(self, elem):node = Node(elem)# 根節點if self.root.data == -1:self.root = nodeself.myQueue.append(self.root)else:treeNode = self.myQueue[0] # 記錄結點if treeNode.lchild is None:treeNode.lchild = nodeself.myQueue.append(treeNode.lchild)else:treeNode.rchild = nodeself.myQueue.append(treeNode.rchild)self.myQueue.popleft() # 彈出已經處理好左右子樹的父結點
我們輸入一個資料,然後根據資料初始化一個節點,放入隊列中,隨後就是訪問的操作了。
樹的三序遍曆就不用說了,基於遞迴的,很好理解,那麼基於隊列以及堆棧的的遍曆呢?
對比下基於隊列的建樹,我們完全可以寫出基於隊列的遍曆, 也是使用隊列來儲存節點,然後輸出左右孩子的資料:
# 層次遍曆 使用隊列def queue_tarversal(self, root):if root is None:returnq = deque()q.append(root)while q:node = q.pop()print(node.data)if node.lchild is not None:q.append(node.lchild)else:q.append(node.rchild)
基於堆棧的呢?聯想下堆棧的特點,我們一路沿著左子樹遍曆下去,同時使用堆棧來儲存元素,然後在彈出遍曆右孩子節點:
# 使用堆棧來遍曆def stack_traversal(self, root):if root is None:returnmystack = []node = rootwhile node or mystack:while node:print(node.data)mystack.append(node)node = node.lchildnode = mystack.pop()node = node.rchild
資料結構是痛點也是基礎,不管怎麼樣都應該好好學習。
完整代碼:
‘‘‘ 二叉樹的建立及實現 (遞迴與非遞迴) ‘‘‘from collections import deque# 樹節點的定義class Node: def __init__(self, data=-1, lchild=None, rchild=None): self.lchild = lchild # 表示左子樹 self.rchild = rchild # 表示右子樹 self.data = data # 表示資料域class Create_Tree: def __init__(self): self.root = Node() # 表示結點 self.myQueue = deque() # 使用隊列不會有太多的記憶體開銷 # 按層次產生樹 def add(self, elem): node = Node(elem) # 根節點 if self.root.data == -1: self.root = node self.myQueue.append(self.root) else: treeNode = self.myQueue[0] # 記錄結點 if treeNode.lchild is None: treeNode.lchild = node self.myQueue.append(treeNode.lchild) else: treeNode.rchild = node self.myQueue.append(treeNode.rchild) self.myQueue.popleft() # 彈出已經處理好左右子樹的父結點 # 遞迴建樹 def traversal_create(self, root): data = input() if data is "#": return None else: root.data = data root.lchild = self.traversal_create(root.lchild) root.rchild = self.traversal_create(root.rchild) return root # 前序走訪輸出 def digui(self, root): if root is None: return print(root.data) self.digui(root.lchild) self.digui(root.rchild) # 使用堆棧來遍曆 def stack_traversal(self, root): if root is None: return mystack = [] node = root while node or mystack: while node: print(node.data) mystack.append(node) node = node.lchild node = mystack.pop() node = node.rchild # 層次遍曆 使用隊列 def queue_tarversal(self, root): if root is None: return q = deque() q.append(root) while q: node = q.pop() print(node.data) if node.lchild is not None: q.append(node.lchild) else: q.append(node.rchild)if __name__ == "__main__": elems = range(10) tree = Create_Tree() for i in elems: # 非遞迴建樹,主要就是根據 隊列FIFO的特點以及廣度遍曆的思路 tree.add(i) # 遞迴建樹 # tree.traversal_create(tree.root) # 遞迴遍曆 tree.digui(tree.root) # 棧遍曆 # tree.stack_traversal(tree.root)
View Code
二叉樹的建立以及遍曆的多種實現(python版)