1. 程式人生 > >Python3&資料結構之二叉樹

Python3&資料結構之二叉樹

實現二叉樹以及遍歷

在電腦科學中,二叉樹是每個結點最多有兩個子樹的樹結構。通常子樹被稱作“左子樹”(left subtree)和“右子樹”(right subtree)。二叉樹常被用於實現二叉查詢樹和二叉堆。

 

二叉樹是遞迴定義的,其結點有左右子樹之分,邏輯上二叉樹有五種基本形態:

(1)空二叉樹——如圖(a);

(2)只有一個根結點的二叉樹——如圖(b);

(3)只有左子樹——如圖(c);

(4)只有右子樹——如圖(d);

(5)完全二叉樹——如圖(e)。

 

 

樹和二叉樹有兩個主要差別:

(1)樹中結點的最大度數沒有限制,而二叉樹結點的最大度數為2;

(2)樹的結點無左、右之分,而二叉樹的結點有左、右之分。

 

二叉樹的性質:

(1)二叉樹第i層上的結點數目最多為2^(i-1)(i>=1);

(2)深度為k的二叉樹至多有(2^k)-1個結點(k>=1);

(3)包含n個結點的二叉樹的高度至少為(logn)+1;(log預設為以2為底);

(4)在任意一棵二叉樹中,若終端結點的個數為n0,度為2的結點數為n2,則n0=n2+1。

 

二叉樹的種類:

(1)滿二叉樹:如果二叉樹中所有分支節點的度都為2,則稱它為一棵滿二叉樹。滿二叉樹是一般二叉樹的子集;

(2)完全二叉樹:對於一棵高度為h的二叉樹,如果其第0層至第h-1層的結點都滿(也就是說,對所有0≤i≤h-1,第i層有2^i個結點)。如果最下一層的結點不滿,則所有結點在最左邊連續排列,空位都在右邊。這樣的二叉樹就是一棵完全二叉樹;

(3)平衡二叉樹:平衡二叉樹(Self-balancing binary search tree)又被稱為AVL樹(有別於AVL演算法),且具有以下性質:它是一 棵空樹或它的左右兩個子樹的高度差的絕對值不超過1,並且左右兩個子樹都是一棵平衡二叉樹。平衡二叉樹的常用實現方法有紅黑樹、AVL、替罪羊樹、Treap、伸展樹等。 最小二叉平衡樹的節點的公式如下 F(n)=F(n-1)+F(n-2)+1 這個類似於一個遞迴的數列,可以參考Fibonacci(斐波那契)數列,1是根節點,F(n-1)是左子樹的節點數量,F(n-2)是右子樹的節點數量。

對於平衡二叉樹要特別注意的是,不要求非葉節點都有兩個子結點,僅要求兩個子樹的高度差的絕對值不超過1,或者為空樹。

 

關於遍歷:

設L、D、R分別表示遍歷左子樹、訪問根結點和遍歷右子樹, 則對一棵二叉樹的遍歷有三種情況:DLR(稱為先根次序遍歷),LDR(稱為中根次序遍歷),LRD (稱為後根次序遍歷)。

 

具體的程式碼部分:

class Node(object):
    def __init__(self,item):
        self.item = item
        self.child1 = None
        self.child2 = None

class Tree(object):
    def __init__(self):
        self.root = None

    def add(self,item):
        node = Node(item)
        if self.root is None:
            self.root = node
        else:
            q = [self.root]

            while True:
                pop_node = q.pop(0)
                if pop_node.child1 is None:
                    pop_node.child1 = node
                    return
                elif pop_node.child2 is None:
                    pop_node.child2 = node
                    return
                else:
                    q.append(pop_node.child1)
                    q.append(pop_node.child2)

    def traverse(self):#層次遍歷(寬度優先遍歷)
        if self.root is None:
            return None
        q = [self.root]
        res = [self.root.item]
        while q != []:
            pop_node = q.pop(0)
            if pop_node.child1 is not None:
                q.append(pop_node.child1)
                res.append(pop_node.child1.item)

            if pop_node.child2 is not None:
                q.append(pop_node.child2)
                res.append(pop_node.child2.item)
        return res

    def preorder(self,root):#先序遍歷
        if root is None:
            return []
        res = [root.item]
        left_item = self.preorder(root.child1)
        right_item = self.preorder(root.child2)
        return res + left_item + right_item

    def inorder(self,root):#中序遍歷
        if root is None:
            return []
        res = [root.item]
        left_item = self.inorder(root.child1)
        right_item = self.inorder(root.child2)
        return left_item + res + right_item

    def postorder(self,root):#後序遍歷
        if root is None:
            return []
        res = [root.item]
        left_item = self.postorder(root.child1)
        right_item = self.postorder(root.child2)
        return left_item + right_item + res

if __name__ == '__main__':
    t = Tree()
    for i in range(10):
        t.add(i)
    print("層序遍歷:",t.traverse())
    print("先序遍歷:", t.preorder(t.root))
    print("中序遍歷:", t.inorder(t.root))
    print("後序遍歷:", t.postorder(t.root))

 

參考文獻:

[1] https://baike.baidu.com/item/%E4%BA%8C%E5%8F%89%E6%A0%91/1602879?fr=aladdin

[2] https://blog.csdn.net/mxz19901102/article/details/80071864