二分搜索樹及相關算法python實現

|-二分查找法
    時間複雜度O(logn)
|-二分搜索樹
    特點:
        高效 不接可以查找數據 插入刪除數據的複雜度都是O(logn)
        可以方便的回答很多數據之間的關係
        min max floor ceil select
    定義:
        二叉樹(不一定是完全二叉樹)
        每個節點的鍵值大於左孩子、小於右孩子
        以左右孩子爲根的子樹仍爲二分搜索樹(遞歸結構)
|-二分搜索樹的遍歷
    深度優先:
        前序遍歷:
        中序遍歷:可以對二分搜索樹進行排序
        後序遍歷:可以用於節點的釋放
    廣度優先:
        層序遍歷:用一個隊列實現
|-刪除一個節點
    尋找二分搜索樹的最大值和最小值:
        一直往左找坐孩子,知道左孩子不存在 該節點爲最小值 最大值同理
    刪除最大值/最小值


    二分搜索樹刪除節點
        只有左孩子:左孩子上移
        只有右孩子:右孩子上移
        左右孩子都有節點:右孩子的最左節點上移
            即找到要刪除的節點的後繼節點 代替該節點
            時間複雜度O(logn)


|-二分搜索樹的侷限性
    同樣的數據 可以對應不同的二分搜索樹
    二分搜索樹可能退化成鏈表 搜索複雜度O(n) 實際上比順序搜索還要慢 因爲存在左右孩子存儲和遞歸的消耗
        解決方案:平衡二叉樹

            紅黑樹實現平衡二叉樹

源代碼:
https://github.com/lzneu/Algrithm_python

from queue import Queue


# 二分查找 有序數組arr 查找target
def binarySearch(arr, n, target):
    # 在arr[l...r]中查找target
    l = 0
    r = n - 1
    while (l <= r):
        # mid = (l+r) // 2 # 此處可能產生整型溢出
        mid = l + (r - l) // 2
        if (arr[mid] == target):
            return mid
        if (target < arr[mid]):
            r = mid - 1
        else:
            l = mid + 1
    # 沒找到 返回-1
    return -1


# 二分搜索樹
class BST:
    # 樹中的節點爲私有的類 外界不需要了解二分搜索樹的具體實現
    class Node:
        def __init__(self, key, value):
            self.key = key
            self.value = value
            self.left = self.right = None

    def __init__(self):
        self.__root = None
        self.__count = 0

    def size(self):
        return self.__count

    def isEmpty(self):
        return self.__count == 0

    # 插入一個新的節點 採用遞歸結構, 返回插入新節點後的二叉搜索樹的根
    def insert(self, key, value):
        self.__root = self.__insert(self.__root, key, value)

    # 以node爲根的二分搜索樹中是否包含鍵值爲key的節點 使用遞歸算法
    def contain(self, key):
        return self.__contain(self.__root, key)

    # 以node爲根結點的二分搜索樹中查找key對應的value, 若value不存在 返回null
    def search(self, key):
        return self.__search(self.__root, key)

    # 二叉樹的前序遍歷
    def preOrder(self):
        self.__preOrder(self.__root)

    # 二叉樹的中序遍歷
    def inOrder(self):
        self.__inOrder(self.__root)

    # 二叉樹的後序遍歷
    def postOrder(self):
        self.__postOrder(self.__root)

    # 二分搜索樹的層序遍歷 利用隊列的數據結構
    def levelOrder(self):
        # 初始化一個隊列
        q = Queue()
        q.put(self.__root)
        while not q.empty():
            node = q.get()
            print(node.key)
            if node.left is not None:
                q.put(node.left)
            if node.right is not None:
                q.put(node.right)

    # 尋找二分搜索樹的最小鍵值
    def minimum(self):
        if self.__count <= 0:
            print('二分搜索樹裏面沒有元素了!!!')
            raise IndexError
        minNode = self.__minimum(self.__root)
        return minNode.key

    # 尋找樹中的最大鍵值
    def maxmum(self):
        if self.__count <= 0:
            print('二分搜索樹裏面沒有元素了!!!')
            raise IndexError
        maxNode  = self.__maxmum(self.__root)
        return maxNode.key

    # 從二分搜索屬樹種刪除最小值所在節點
    def removeMin(self):
        if self.__root is not None:
            self.__root = self.__removeMin(self.__root)

    def removeMax(self):
        if self.__root is not None:
            self.__root = self.__removeMax(self.__root)

    # 從二分搜索樹種刪除鍵值爲key的節點
    def remove(self, key):
        self.__root = self.__remove(self.__root, key)

    '''
    二分搜索樹輔助函數
    '''
    # 刪除以node爲根的二分搜索樹種鍵值爲key的節點,遞歸算法
    # 返回刪除後的節點後新的二分搜索樹
    def __remove(self, node, key):
        if node is None:
            return None
        # 遞歸尋找
        if key > node.key:
            node.right = self.__remove(node.right, key)
            return node
        elif key < node.key:
            node.left = self.__remove(node.left, key)
            return node
        else:  # key==node.key的情況
            # 待刪除的節點左子樹爲空
            if node.left is None:
                rightNode = node.right
                node.right = None
                self.__count -= 1
                return rightNode
            # 待刪除的節點右子樹爲空
            if node.right is None:
                leftNode = node.left
                node.left = None
                self.__count -= 1
                return leftNode

            # 待刪除的節點左右節點都不爲空的情況
            # 找到比待刪除節點大的最小節點 即待刪除節點右子樹的最小節點
            # 用這個節點頂替待刪除節點的位置
            successor = self.Node(node.key, node.value)
            self.__count += 1
            successor.right = self.__removeMin(node.right)
            successor.left = node.left

            node.left = node.right = None
            self.__count -= 1

            return successor


    # 刪除掉以node爲根的二分搜索書中的最小節點
    # 返回刪除節點後的二分搜索樹的根節點
    def __removeMin(self, node):
        if node.left is not None:
            rightNode  = node.right
            print(node.key)
            print('已經刪除')
            node.right = None
            self.__count -= 1
            return rightNode

        node.left = self.__removeMin(node.left)
        return node

    # 刪除掉以node爲根的二分搜索書中的最大節點
    # 返回刪除節點後的二分搜索樹的根節點
    def __removeMax(self, node):
        if node.right is not None:
            leftNode = node.left
            print(node.key)
            print('已經刪除')
            node.left = None
            self.__count -= 1
            return leftNode
        node.right = self.__removeMax(node.right)
        return node

    def __minimum(self, node):
        if (node.left is None):
            return node
        return self.__minimum(node.left)

    def __maxmum(self, node):
        if node.right is None:
            return node
        return self.__maxmum(node.right)

    def __insert(self, node, key, value):
        if (node is None):
            self.__count += 1
            return self.Node(key, value)

        if (key == node.key):
            node.value = value
        elif (key > node.key):
            node.right = self.__insert(node.right, key, value)
        else:
            node.left = self.__insert(node.left, key, value)
        return node

    def __contain(self, node, key):

        if node is None:
            return False
        if (key == node.key):
            return True
        elif (key > node.key):
            return self.__contain(node.right, key)
        else:
            return self.__contain(node.left, key)

    def __search(self, node, key):
        if node is None:
            return None
        if key == node.key:
            return node.value
        elif key > node.key:
            return self.__search(node.right, key)
        else:
            return self.__search(node.left, key)

    def __preOrder(self, node):
        if node is not None:
            print(node.key)
            self.__preOrder(node.left)
            self.__preOrder(node.right)

    def __inOrder(self, node):
        if node is not None:
            self.__inOrder(node.left)
            print(node.key)
            self.__inOrder(node.right)

    def __postOrder(self, node):
        if node is not None:
            self.__postOrder(node.left)
            self.__postOrder(node.right)
            print(node.key)


from tools import *
if __name__ == '__main__':
    n = 100000
    start = 0
    end = 100000
    arr = genNearlyOrderArray(n, swapTimes=50000)
    # arr = genRandomArray(n, start, end)
    arr2 = arr.copy()
    arr3 = arr.copy()
    arr4 = arr.copy()
    arr5 = arr.copy()
    print(arr)
    bst = BST()
    # 測試的搜索二叉樹的鍵類型爲int 值類型爲string
    for i in range(n):
        bst.insert(arr[i], str(arr[i]))
    maxN = bst.maxmum()
    print(maxN)
    bst.remove(99999)
    print(bst.maxmum())

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