二叉查詢樹(binary search tree)——python實現
阿新 • • 發佈:2019-01-02
二叉查詢樹(binary search tree)
顧名思義二叉查詢樹中每個節點至多有兩個子節點,並且還對儲存於每個節點中的關鍵字值有個小小的要求,即只要這個節點有左節點或右節點,那麼其關鍵字值總的大於其左節點的關鍵字值,小於其右節點的關鍵字值,如下圖:
因為樹的結構特性,很適合使用遞迴的方式去操作,下面的實現中均是以遞迴的方式實現: 下面僅給出了python的實現,一是因為程式碼太長,二是python的實現是我對著C語言實現改過來的,基本沒什麼差別; 主要實現的方法有:
- 遍歷:
前序:preorder()——理根節點→處理左子樹→處理右子樹
中序:inorder()——處理左子樹→處理根節點→處理右子樹
後序:postorder()——處理左子樹→處理右子樹→處理根節點
- 插入:
insert(key)——將關鍵字值為key的節點插入到適當的位置(註釋裡面的是非遞迴實現)
- 刪除:
delete(key)——將關鍵字值為key的節點從樹中刪掉(註釋中給了說明)
- 獲取高度:
height()
- 獲取樹中的節點數:
count()
- 查詢:
find(key)——查詢關鍵字值為key的節點(二叉查詢樹的一個重要應用就是在查詢中)
- 獲取樹中最大key值節點和最key值小節點:
find_max()
find_min()
;;;
class tree_node: def __init__(self, key = None, left = None, right = None): self.key = key self.left = left self.right = right class binary_search_tree: def __init__(self): self.root = None def preorder(self): print 'preorder: ', self.__preorder(self.root) print def __preorder(self, root): if not root: return print root.key, self.__preorder(root.left) self.__preorder(root.right) def inorder(self): print 'inorder: ', self.__inorder(self.root) print def __inorder(self, root): if not root: return self.__inorder(root.left) print root.key, self.__inorder(root.right) def postorder(self): print 'postorder: ', self.__postorder(self.root) print def __postorder(self, root): if not root: return self.__postorder(root.left) self.__postorder(root.right) print root.key, def insert(self, key): '''recursion''' self.root = self.__insert(self.root, key) def __insert(self, root, key): if not root: root = tree_node(key) else: if key < root.key: root.left = self.__insert(root.left, key) elif key > root.key: root.right = self.__insert(root.right, key) else: print key, 'is already in tree' return root ##non-recursion ## def insert(self, key): ## if not self.root: ## self.root = tree_node(key) ## else: ## cur = self.root ## while True: ## if key < cur.key: ## if not cur.left: ## cur.left = tree_node(key) ## break ## cur = cur.left ## elif key > cur.key: ## if not cur.right: ## cur.right = tree_node(key) ## break ## cur = cur.right ## else: ## print key, 'in tree' ## break def height(self): return self.__height(self.root) def __height(self, root): if not root: return -1 left_height = self.__height(root.left) right_height = self.__height(root.right) #return 1+(left_height if left_height>right_height else right_height)#這種方式是自己寫的,後面兩種高大上的是網上偷學的^_^ #return 1+[left_height,right_height][left_height<right_height] return 1+(left_height>right_height and [left_height] or [right_height])[0] def count(self): '''elements in tree''' return self.__count(self.root) def __count(self, root): if not root: return 0 return 1+self.__count(root.left)+self.__count(root.right) def delete(self, key): self.root = self.__delete(self.root, key) ## ##刪除操作: ##首先找到刪除的節點, ##1. 如果左右子樹都不為空,則找到右子樹中最小的節點min,用min.key代替刪除節點的key,然後再到右子 ## 樹中刪除min節點,因為min沒有左節點,所以刪除它的話只需要用它的右節點代替它(如果有右節點); ##2. 如果左子樹或者右子樹不為空,則直接代替掉 ##3. 如果左右均空即葉子節點,直接刪掉 def __delete(self, root, key): if not root: print 'not find key: ', key elif key < root.key: root.left = self.__delete(root.left, key) elif key > root.key: root.right = self.__delete(root.right, key) elif root.left and root.right: #found right_min = self.__find_min(self.root.right) root.key = right_min.key root.right = self.__delete(root.right, right_min.key) elif root.left: root = root.left elif root.right: root = root.right else: root = None #python的GC會在沒有引用指向物件的時候銷燬物件 return root def find(self, key): node = self.__find(self.root, key) if not node: print 'not found' return node def __find(self, root, key): if not root: return None if key < root.key: return self.__find(root.left, key) elif key > root.key: return self.__find(root.right, key) else: return root def find_min(self): return self.__find_min(self.root) def __find_min(self, root): if not root.left: return root return self.__find_min(root.left) def find_max(self): return self.__find_max(self.root) def __find_max(self, root): if not root.right: return root return self.__find_max(root.right) def main(): import random root = binary_search_tree() for i in random.sample([j for j in range(1, 100)], 5): root.insert(i) print 'insert: ' root.insert(78) root.insert(101) root.insert(14) root.preorder() root.inorder() root.postorder() print 'height: ', root.height() print 'count: ', root.count() print 'min: ', root.find_min().key print 'max: ', root.find_max().key print 'delete: ' root.delete(101) root.delete(12) root.preorder() root.inorder() root.postorder() print root.find(71) print root.find(78) print 'height: ', root.height() print 'count: ', root.count() print 'min: ', root.find_min().key print 'max: ', root.find_max().key if __name__ == '__main__': main()