二叉樹是很重要的數據結構,在面試還是日常開發中都是很重要的角色。
首先是建立樹的過程,對比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 None else: root.data = data root.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 = 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 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)
基於堆棧的呢?聯想下堆棧的特點,我們一路沿着左子樹遍歷下去,同時使用堆棧來存儲元素,然后在彈出遍歷右孩子節點:
# 使用堆棧來遍歷 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
數據結構是難點也是基礎,不管怎么樣都應該好好學習。
完整代碼:

''' 二叉樹的建立及實現 (遞歸與非遞歸) ''' 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)