1. 程式人生 > >七大查詢演算法之樹表查詢---二叉樹查詢演算法

七大查詢演算法之樹表查詢---二叉樹查詢演算法

二叉樹查詢演算法

       二叉查詢樹是先對待查詢的資料進行生成樹,確保樹的左分支的值小於右分支的值,然後在就行和每個節點的父節點比較大小,查詢最適合的範圍。 這個演算法的查詢效率很高,但是如果使用這種查詢方法要首先建立樹。

原理: 

       二叉查詢樹(BinarySearch Tree,也叫二叉搜尋樹 BST,或稱二叉排序樹Binary Sort Tree)或者是一棵空樹,或者是具有下列性質的二叉樹:

  1)若任意節點的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值;

  2)若任意節點的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值;

  3)任意節點的左、右子樹也分別為二叉查詢樹;

  4) 沒有鍵值相等的節點(no duplicate nodes)。

BST 中實現查詢元素:

根據BST的特性,對於每個節點:

  1. 如果目標值等於節點的值,則返回節點
  2. 如果目標值小於節點的值,則繼續在左子樹中搜索
  3. 如果目標值大於節點的值,則繼續在右子樹中搜索

在上面的二叉搜尋樹中搜索目標值為 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. 根據節點值與目標節點值的關係,搜尋左子樹或右子樹;
  2. 重複步驟 1 直到到達外部節點;
  3. 根據節點的值與目標節點的值的關係,將新節點新增為其左側或右側的子節點。

è¿éåå¾çæè¿°

這樣,我們就可以新增一個新的節點並依舊維持二叉搜尋樹的性質。

    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)