python data structure and algorithm ---- binary tree

Basic Concepts of Binary Tree

A binary tree is a tree structure with at most two subtrees per node. Usually subtrees are called "left subtree" and "right subtree"

Properties (Characteristics) of Binary Trees

Property 1:  There are at most 2^(i-1) nodes (i>0) on the i-th level of a binary tree.
Property 2:  A binary tree of depth k has at most 2^k - 1 nodes (k>0)
Property 3:  For any binary tree, if the number of leaf nodes is N0, and the total number of nodes with degree 2 is N2, then N0=N2+1;
Property 4: The depth of a complete binary tree with n nodes must be log2(n+1)
property 5: For a complete binary tree, if the number is from top to bottom and from left to right, then the number of the node number i, its left child number must be 2i, and its right child number must be 2i+1; The number of the parent must be i/2 (the root is the root when i=1, except)

(1) Complete binary tree - If the height of the binary tree is set to be h, the number of nodes in other layers (1 ~ h-1) has reached the maximum number except for the h-th layer, and the h-th layer has leaf nodes and leaves Nodes are arranged in order from left to right, which is a complete binary tree.


(2) Full binary tree—a binary tree in which every node except the leaf node has left and right cotyledons and the leaf nodes are at the bottom.

Node representation of binary tree and tree creation

By using the Node class to define three properties, which are the value of elem itself, as well as the left child of lchild and the right child of rchild

#Construct node class
class Node():
    def __init__(self,item):
        self.elem=item
        self.lchild=None
        self.rchild=None

Tree creation, create a tree class, and give a root root node, which is empty at first, and then add nodes

#construct the tree class
class Tree():
    def __init__(self):
        self.root=None
    #add element
    def add(self,item):
        node=Node(item)
        queue = [self.root]
        # If the tree is empty, assign a value to the root node
        if self.root is None:
            self.root=node
            return
        # Perform a hierarchical traversal of the existing nodes
        while queue:
            # Pop the first element of the queue
            cur_queue=queue.pop(0)
            # If the left and right subtrees are not empty, join the queue and continue to judge
            if cur_queue.lchild is None:
                cur_queue.lchild=node
                return
            else:
                queue.append(cur_queue.lchild)
            if cur_queue.rchild is None:
                cur_queue.rchild=node
                return
            else:
                queue.append(cur_queue.rchild)

traversal of binary tree

Tree traversal is an important operation of the tree. The so-called traversal refers to the access to the information of all nodes in the tree, that is, each node in the tree is visited once and only once. We call this visit to all nodes traversal. Then the two important traversal modes of the tree are depth-first traversal and breadth-first traversal. Depth-first generally uses recursion, and breadth-first generally uses queue. In general, most algorithms that can be implemented recursively can also be implemented using stacks.

depth-first traversal

For a binary tree, depth first search (Depth First Search) is to traverse the nodes of the tree along the depth of the tree, and search for branches of the tree as deep as possible.
Then there are three important methods for deep traversal. These three methods are often used to visit the nodes of the tree, and the difference between them is the order in which each node is visited. These three traversals are called preorder, inorder, and postorder. Let us give their detailed definitions, and then look at their applications with examples.

  • Preorder traversal In preorder traversal, we first visit the root node, then recursively use preorder traversal to visit the left subtree, and then recursively use preorder traversal to visit the right subtree
    root node -> left subtree -> right subtree
  • In-order traversal In in-order traversal, we recursively use in-order traversal to access the left subtree, then access the root node, and finally recursively use in-order traversal to access the right subtree
    Left subtree -> root node -> right subtree
  • Post-order traversal In post-order traversal, we first recursively use post-order traversal to access the left subtree and right subtree, and finally visit the root node
    left subtree -> right subtree -> root node
#depth first traversal
    '''
    Preorder traversal: around the root
    Inorder traversal: left root right
    Postorder Traversal: Left and Right Roots
    '''
    #Recursive implementation of preorder traversal: root --> left --> right
    def preorder(self,node):
        if node is None:
            return
        print(node.elem,end=' ')
        self.preorder(node.lchild)
        self.preorder(node.rchild)

    # Recursive implementation of in-order traversal: left --> root --> right
    def inorder(self,node):
        if node is None:
            return
        self.inorder(node.lchild)
        print(node.elem,end=' ')
        self.inorder(node.rchild)

    # Recursive implementation of post-order traversal: left --> right --> root
    def postorder(self,node):
        if node is None:
            return
        self.postorder(node.lchild)
        self.postorder(node.rchild)
        print(node.elem,end=' ')


Breadth-first traversal (hierarchical traversal)

Starting at the root of the tree, traverse the nodes of the entire tree from top to bottom, left to right

# breadth-first traversal
    def breadth_travel(self):
        """Using queues to implement tree level traversal"""
        if self.root is None:
            return
        queue=[self.root]
        while queue:
            node=queue.pop(0)
            print(node.elem,end=' ')
            if node.lchild is not None:
                queue.append(node.lchild)
            if node.rchild is not None:
                queue.append(node.rchild)

The overall code for traversing the binary tree:

#Construct node class
class Node():
    def __init__(self,item):
        self.elem=item
        self.lchild=None
        self.rchild=None
#construct the tree class
class Tree():
    def __init__(self):
        self.root=None
    #add element
    def add(self,item):
        node=Node(item)
        queue = [self.root]
        # If the tree is empty, assign a value to the root node
        if self.root is None:
            self.root=node
            return
        # Perform a hierarchical traversal of the existing nodes
        while queue:
            # Pop the first element of the queue
            cur_queue=queue.pop(0)
            # If the left and right subtrees are not empty, join the queue and continue to judge
            if cur_queue.lchild is None:
                cur_queue.lchild=node
                return
            else:
                queue.append(cur_queue.lchild)
            if cur_queue.rchild is None:
                cur_queue.rchild=node
                return
            else:
                queue.append(cur_queue.rchild)

    # breadth-first traversal
    def breadth_travel(self):
        """Using queues to implement tree level traversal"""
        if self.root is None:
            return
        queue=[self.root]
        while queue:
            node=queue.pop(0)
            print(node.elem,end=' ')
            if node.lchild is not None:
                queue.append(node.lchild)
            if node.rchild is not None:
                queue.append(node.rchild)

    #depth first traversal
    '''
    Preorder traversal: around the root
    Inorder traversal: left root right
    Postorder Traversal: Left and Right Roots
    '''
    #Recursive implementation of preorder traversal: root --> left --> right
    def preorder(self,node):
        if node is None:
            return
        print(node.elem,end=' ')
        self.preorder(node.lchild)
        self.preorder(node.rchild)

    # Recursive implementation of in-order traversal: left --> root --> right
    def inorder(self,node):
        if node is None:
            return
        self.inorder(node.lchild)
        print(node.elem,end=' ')
        self.inorder(node.rchild)

    # Recursive implementation of post-order traversal: left --> right --> root
    def postorder(self,node):
        if node is None:
            return
        self.postorder(node.lchild)
        self.postorder(node.rchild)
        print(node.elem,end=' ')

if __name__ == '__main__':
    tree=Tree()
    tree.add(0)
    tree.add(1)
    tree.add(2)
    tree.add(3)
    tree.add(4)
    tree.add(5)
    tree.add(6)
    tree.add(7)
    tree.add(8)
    tree.add(9)
    print('----Breadth-first traversal----')
    tree.breadth_travel()
    print()
    print('------preorder traversal------')
    tree.preorder(tree.root)
    print()
    print('------Inorder traversal------')
    tree.inorder(tree.root)
    print()
    print('------post-order traversal------')
    tree.postorder(tree.root)
----Breadth-first traversal----
0 1 2 3 4 5 6 7 8 9
------Pre-order traversal------
0 1 3 7 8 4 9 2 5 6
------Inorder Traversal------
7 3 8 1 9 4 0 5 2 6
------Post-order traversal------
7 8 3 9 4 1 5 6 2 0




Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325651994&siteId=291194637