1. 程式人生 > >二叉查詢樹(binary search tree)——python實現

二叉查詢樹(binary search tree)——python實現

二叉查詢樹(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()