七大查詢演算法之樹表查詢---二叉樹查詢演算法
阿新 • • 發佈:2018-12-16
二叉樹查詢演算法
二叉查詢樹是先對待查詢的資料進行生成樹,確保樹的左分支的值小於右分支的值,然後在就行和每個節點的父節點比較大小,查詢最適合的範圍。 這個演算法的查詢效率很高,但是如果使用這種查詢方法要首先建立樹。
原理:
二叉查詢樹(BinarySearch Tree,也叫二叉搜尋樹 BST,或稱二叉排序樹Binary Sort Tree)或者是一棵空樹,或者是具有下列性質的二叉樹:
1)若任意節點的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值;
2)若任意節點的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值;
3)任意節點的左、右子樹也分別為二叉查詢樹;
4) 沒有鍵值相等的節點(no duplicate nodes)。
BST 中實現查詢元素:
根據BST的特性,對於每個節點:
- 如果目標值等於節點的值,則返回節點
- 如果目標值小於節點的值,則繼續在左子樹中搜索
- 如果目標值大於節點的值,則繼續在右子樹中搜索
在上面的二叉搜尋樹中搜索目標值為 4 的節點
def search(self, node, parent, data): if node is None: return False, node, parent if node.data == data: return True, node, parent if node.data > data: return self.search(node.leftChild, node, data) else: return self.search(node.rightChild, node, data)
BST 中實現插入元素:
與搜尋操作類似,對於每個節點,我們將:
- 根據節點值與目標節點值的關係,搜尋左子樹或右子樹;
- 重複步驟 1 直到到達外部節點;
- 根據節點的值與目標節點的值的關係,將新節點新增為其左側或右側的子節點。
這樣,我們就可以新增一個新的節點並依舊維持二叉搜尋樹的性質。
def insert(self, data): flag, n, p = self.search(self.root, self.root, data) if not flag: new_node = BSTNode(data) if data > p.data: p.rightChild = new_node else: p.leftChild = new_node
BST中實現刪除操作:
刪除要比我們前面提到過的兩種操作複雜許多。有許多不同的刪除節點的方法,根據其子節點的個數,我們需考慮以下三種情況:
1. 如果目標節點沒有子節點,我們可以直接移除該目標節點。 2. 如果目標節只有一個子節點,我們可以用其子節點作為替換。 3. 如果目標節點有兩個子節點,我們需要用其中序後繼節點或者前驅節點來替換,再刪除該目標節點。
例 1:目標節點沒有子節點
例 2:目標節只有一個子節點
例 3:目標節點有兩個子節點
def delete(self, root, data):
flag, n, p = self.search(root, root, data)
if flag is False:
return "關鍵字不存在,刪除失敗"
else:
if n.leftChild is None:
if n == p.leftChild:
p.leftChild = n.rightChild
else:
p.rightChild = n.rightChild
del p
elif n.rightChild is None:
if n == p.leftChild:
p.leftChild = n.leftChild
else:
p.rightChild = n.leftChild
del p
else: # 左右子樹均不為空
pre = n.rightChild
if pre.leftChild is None:
n.data = pre.data
n.rightChild = pre.rightChild
del pre
else:
next = pre.leftChild
while next.leftChild is not None:
pre = next
next = next.leftChild
n.data = next.data
pre.leftChild = next.rightChild
del p
程式碼分析:
class BSTNode:
def __init__(self, data):
self.data = data
self.leftChild = None
self.rightChild = None
class BST:
def __init__(self, node_list):
self.root = BSTNode(node_list[0])
for data in node_list[1:]:
self.insert(data)
def search(self, node, parent, data):
if node is None:
return False, node, parent
if node.data == data:
return True, node, parent
if node.data > data:
return self.search(node.leftChild, node, data)
else:
return self.search(node.rightChild, node, data)
def insert(self, data):
flag, n, p = self.search(self.root, self.root, data)
if not flag:
new_node = BSTNode(data)
if data > p.data:
p.rightChild = new_node
else:
p.leftChild = new_node
def delete(self, root, data):
flag, n, p = self.search(root, root, data)
if flag is False:
return "關鍵字不存在,刪除失敗"
else:
if n.leftChild is None:
if n == p.leftChild:
p.leftChild = n.rightChild
else:
p.rightChild = n.rightChild
del p
elif n.rightChild is None:
if n == p.leftChild:
p.leftChild = n.leftChild
else:
p.rightChild = n.leftChild
del p
else: # 左右子樹均不為空
pre = n.rightChild
if pre.leftChild is None:
n.data = pre.data
n.rightChild = pre.rightChild
del pre
else:
next = pre.leftChild
while next.leftChild is not None:
pre = next
next = next.leftChild
n.data = next.data
pre.leftChild = next.rightChild
del p
# 先序遍歷
def preOrderTraverse(self, node):
if node is not None:
print(node.data)
self.preOrderTraverse(node.leftChild)
self.preOrderTraverse(node.rightChild)
# 中序遍歷
def inOrderTraverse(self, node):
if node is not None:
self.inOrderTraverse(node.leftChild)
print(node.data)
self.inOrderTraverse(node.rightChild)
# 後序遍歷
def postOrderTraverse(self, node):
if node is not None:
self.postOrderTraverse(node.leftChild)
self.postOrderTraverse(node.rightChild)
print(node.data)