python實現二叉查找樹

1. 定義

二叉查找樹(Binary Search Tree),又稱爲二叉搜索樹、二叉排序樹。其或者是一棵空樹;或者是具有以下性質的二叉樹:

  • 若左子樹不空,則左子樹上所有結點的值均小於或等於它的根結點的值
  • 若右子樹不空,則右子樹上所有結點的值均大於或等於它的根結點的值
  • 左、右子樹也分別爲二叉排序樹
    圖 1
    圖 1

    樹中節點的定義如下:
class Node:
    def __init__(self, data):
        self.data = data
        self.lchild = None
        self.rchild = None

2. 查找與插入

當二叉查找樹不爲空時:

  • 首先將給定值與根結點的關鍵字比較,若相等,則查找成功
  • 若小於根結點的關鍵字值,遞歸查左子樹
  • 若大於根結點的關鍵字值,遞歸查右子樹
  • 若子樹爲空,查找不成功

二叉排序樹是一種動態樹表。其特點是:樹的結構通常不是一次生成的,而是在查找過程中,當樹中不存在關鍵字等於給定值的結點時再進行插入。新插入的結點一定是一個新添加的葉子結點,並且是查找不成功時查找路徑上訪問的最後一個結點的左孩子或右孩子結點。如下圖所示:

這裏寫圖片描述

插入與搜索的代碼:

     # 搜索
    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.lchild, node, data)
        else:
            return self.search(node.rchild, node, data)

    # 插入
    def insert(self, data):
        flag, n, p = self.search(self.root, self.root, data)
        if not flag:
            new_node = Node(data)
            if data > p.data:
                p.rchild = new_node
            else:
                p.lchild = new_node

3. 刪除

二叉查找樹的刪除操作分爲三種情況:

  1. 如果待刪除的節點是葉子節點,那麼可以立即被刪除,如下圖所示:
    這裏寫圖片描述
  2. 如果節點只有一個兒子,則將此節點parent的指針指向此節點的兒子,然後刪除節點,如下圖所示:
    這裏寫圖片描述
  3. 如果節點有兩個兒子,則將其右子樹的最小數據代替此節點的數據,並將其右子樹的最小數據刪除,如下圖所示:
    這裏寫圖片描述

刪除節點的代碼:

    # 刪除
    def delete(self, root, data):
        flag, n, p = self.search(root, root, data)
        if flag is False:
            print "無該關鍵字,刪除失敗"
        else:
            if n.lchild is None:
                if n == p.lchild:
                    p.lchild = n.rchild
                else:
                    p.rchild = n.rchild
                del n
            elif n.rchild is None:
                if n == p.lchild:
                    p.lchild = n.lchild
                else:
                    p.rchild = n.lchild
                del n
            else:  # 左右子樹均不爲空
                pre = n.rchild
                if pre.lchild is None:
                    n.data = pre.data
                    n.rchild = pre.rchild
                    del pre
                else:
                    next = pre.lchild
                    while next.lchild is not None:
                        pre = next
                        next = next.lchild
                    n.data = next.data
                    pre.lchild = next.rchild
                    del next

4. 遍歷

1. 先序遍歷

訪問順序如下:

  • 訪問根節點
  • 先序遍歷左子樹
  • 先序遍歷右子樹

以圖 1爲例,訪問順序爲:4,2,1,3,5,6

    # 先序遍歷
    def preOrderTraverse(self, node):
        if node is not None:
            print node.data,
            self.preOrderTraverse(node.lchild)
            self.preOrderTraverse(node.rchild)

2. 中序遍歷

訪問順序如下:

  • 中序遍歷左子樹
  • 訪問根節點
  • 中序遍歷右子樹

以圖 1爲例,訪問順序爲:1,2,3,5,7,9

    # 中序遍歷
    def inOrderTraverse(self, node):
        if node is not None:
            self.inOrderTraverse(node.lchild)
            print node.data,
            self.inOrderTraverse(node.rchild)

3. 後序遍歷

訪問順序如下:

  • 後序遍歷左子樹
  • 後序遍歷右子樹
  • 訪問根節點
    以圖 1爲例,訪問順序爲:1,3,2,9,7,5
    # 後序遍歷
    def postOrderTraverse(self, node):
        if node is not None:
            self.postOrderTraverse(node.lchild)
            self.postOrderTraverse(node.rchild)
            print node.data,

5. 完整代碼

# encoding: utf-8
class Node:
    def __init__(self, data):
        self.data = data
        self.lchild = None
        self.rchild = None

class BST:
    def __init__(self, node_list):
        self.root = Node(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.lchild, node, data)
        else:
            return self.search(node.rchild, node, data)

    # 插入
    def insert(self, data):
        flag, n, p = self.search(self.root, self.root, data)
        if not flag:
            new_node = Node(data)
            if data > p.data:
                p.rchild = new_node
            else:
                p.lchild = new_node

    # 刪除
    def delete(self, root, data):
        flag, n, p = self.search(root, root, data)
        if flag is False:
            print "無該關鍵字,刪除失敗"
        else:
            if n.lchild is None:
                if n == p.lchild:
                    p.lchild = n.rchild
                else:
                    p.rchild = n.rchild
                del p
            elif n.rchild is None:
                if n == p.lchild:
                    p.lchild = n.lchild
                else:
                    p.rchild = n.lchild
                del p
            else:  # 左右子樹均不爲空
                pre = n.rchild
                if pre.lchild is None:
                    n.data = pre.data
                    n.rchild = pre.rchild
                    del pre
                else:
                    next = pre.lchild
                    while next.lchild is not None:
                        pre = next
                        next = next.lchild
                    n.data = next.data
                    pre.lchild = next.rchild
                    del p


    # 先序遍歷
    def preOrderTraverse(self, node):
        if node is not None:
            print node.data,
            self.preOrderTraverse(node.lchild)
            self.preOrderTraverse(node.rchild)

    # 中序遍歷
    def inOrderTraverse(self, node):
        if node is not None:
            self.inOrderTraverse(node.lchild)
            print node.data,
            self.inOrderTraverse(node.rchild)

    # 後序遍歷
    def postOrderTraverse(self, node):
        if node is not None:
            self.postOrderTraverse(node.lchild)
            self.postOrderTraverse(node.rchild)
            print node.data,

a = [49, 38, 65, 97, 60, 76, 13, 27, 5, 1]
bst = BST(a)  # 創建二叉查找樹
bst.inOrderTraverse(bst.root)  # 中序遍歷

bst.delete(bst.root, 49)
print
bst.inOrderTraverse(bst.root)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章