1/ Tree definition and basic terminology

Tree structure is a kind of important nonlinear data structure, among which tree and binary tree are the most commonly used hierarchical structure defined by branch relation. Tree structure exists widely in the objective world, such as the family tree of human society and various social organizations; It is also widely used in the field of computer, such as in the compiler program, the tree can be used to represent the grammatical structure of the source program; In database system, tree structure is also one of the important organization forms of information. In machine learning, decision tree, random forest, GBDT and so on are common tree models. In the tree structure, there are three types of nodes, namely root node, middle node and leaf node. In a tree, there is only one root node and no left and right child nodes are leaf nodes. How many layers a tree has, and how deep (or tall) the tree is. Based on the height of the tree, we can know how many nodes the tree has at most. And 2 to the k minus 1 nodeCopy the code

Definition and basic properties of 2/ binary tree

Binary Tree is a special Tree structure, which is characterized by each node has at most two subtrees (that is, there is no node with degree greater than 2 in the Binary Tree), and the subtrees of the Binary Tree are divided into left and right, and the order of the subtrees cannot be arbitrarily reversed (ordered Tree).Copy the code

According to the definition of binary tree, it has the following important properties as shown in the figure below:

3 over full binary tree

A tree is a full binary tree if its depth is K and it has 2 to the k minus 1 nodes. Full binary tree, and every node except the leaf node has 2 child nodes. For a full binary tree, you can never add a new node.Copy the code

4/ binary tree traversal

The so-called binary tree traversal refers to how to patrol each node in the tree according to a certain search path, so that each node is visited once, and only once. For binary trees, the common traversal methods are: sequential traversal, middle traversal, post-sequential traversal, and hierarchical traversal. These traversal methods are generally implemented using recursive algorithms. The operation of sequential traversal is defined as: if the binary tree is empty, the operation is empty; Otherwise (1) access the root node; (2) Traverse the left subtree in order first; (3) Traverse the right subtree in order first. The operation of middle-order traversal is defined as: if the binary tree is empty, the operation is empty; Otherwise, the order in (1) traverses the left subtree; (2) Access the root node; (3) In order to traverse the right subtree. The operation of post-order traversal is defined as: if the binary tree is empty, the operation is empty; Otherwise, (1) the left subtree is traversed sequentially; (2) The right subtree is traversed sequentially; (3) Access the root node. The operation of sequence traversal is defined as: if the binary tree is empty, it is empty; Otherwise, access is hierarchical from top to bottom and left to right. For example, the following figure shows the sequence traversal: 18 7 3 4 11 5 1 3 6 2 4 The sequence traversal is: 3 7 4 18 1 5 3 11 2 6 4 the sequence traversal is: 3 4 7 1 3 5 2 4 6 11 [[18], [7, 11], [3, 4, 5, 6], [1, 3, 2, 4]Copy the code

5/ Binary tree python code implementation

from graphviz import Digraph
import uuid
from random import sample

# binary tree class
class BTree(object) :

    # initialization
    # build a binary tree
    def __init__(self, data=None, left=None, right=None) :
        # For a node, it consists of three parts, and data, left child, right child
        self.data = data    # data fields
        self.left = left    # left subtree
        self.right = right  # right subtree
        self.dot = Digraph(comment='Binary Tree')

    # preorder traversal
    def preorder(self) :
    
        if self.data is not None:
            print(self.data, end=' ')
        if self.left is not None:
            self.left.preorder()
        if self.right is not None:
            self.right.preorder()

    # order traversal
    def inorder(self) :
    
        if self.left is not None:
            self.left.inorder()
        if self.data is not None:
            print(self.data, end=' ')
        if self.right is not None:
            self.right.inorder()

    Post order traversal
    def postorder(self) :
    
        if self.left is not None:
            self.left.postorder()
        if self.right is not None:
            self.right.postorder()
        if self.data is not None:
            print(self.data, end=' ')

    # sequence traversal
    def levelorder(self) :
    
        Return the left child of a node
        def LChild_Of_Node(node) :
            return node.left if node.left is not None else None
        Return the right child of a node
        def RChild_Of_Node(node) :
            return node.right if node.right is not None else None

        # order traversal list
        level_order = []
        Whether to add data from the root node
        if self.data is not None:
            level_order.append([self])

        # The height of the binary tree
        height = self.height()
        if height >= 1:
            Add nodes instead of data to level_ORDER for the second and subsequent levels
            for _ in range(2, height + 1):
                level = []  # Nodes for this layer
                for node in level_order[-1] :Add the left child if the left child is not empty
                    if LChild_Of_Node(node):
                        level.append(LChild_Of_Node(node))
                    If the right child is not empty, add the right child
                    if RChild_Of_Node(node):
                        level.append(RChild_Of_Node(node))
                If the layer is not empty, add it
                if level:
                    level_order.append(level)

            Fetch data from each layer
            for i in range(0, height):  # layer
                for index in range(len(level_order[i])):
                    level_order[i][index] = level_order[i][index].data

        return level_order


    # The height of the binary tree
    def height(self) :
        # empty tree height = 0,
        if self.data is None:
            return 0
            
        The height of the root node is 1
        elif self.left is None and self.right is None:
            return 1
        
        # As long as one is not None, recurse
        elif self.left is None and self.right is not None:
            return 1 + self.right.height()
            
        elif self.left is not None and self.right is None:
            return 1 + self.left.height()
        
        # return a maximum value for the depth of the tree
        else:
            return 1 + max(self.left.height(), self.right.height())


    # the leaves of a binary tree
    def leaves(self) :
        # If there is no data field, return None
        if self.data is None:
            return None
        
        # No left child, no right child, such nodes are leaf nodes, print out
        elif self.left is None and self.right is None:
            print(self.data, end=' ')
        
        # Recurse if there is a right child
        elif self.left is None and self.right is not None:
            self.right.leaves()
        
        # Recurse if there are left children
        elif self.right is None and self.left is not None:
            self.left.leaves()
        
        # If both the left and right children have it, then both sides are recursive
        else:
            self.left.leaves()
            self.right.leaves()


    # Use Graphviz to visualize binary trees
    def print_tree(self, save_path='./Binary_Tree.gv', label=False) :

        # colors for labels of nodes
        colors = ['skyblue'.'tomato'.'orange'.'purple'.'green'.'yellow'.'pink'.'red']

        Draw a binary tree with a node as the root
        def print_node(node, node_tag) :
            # node color
            color = sample(colors,1) [0]
            if node.left is not None:
                left_tag = str(uuid.uuid1())            # Left node data
                self.dot.node(left_tag, str(node.left.data), style='filled', color=color)    # left node
                label_string = 'L' if label else ' '    # Whether to label the connection line to indicate a left subtree
                self.dot.edge(node_tag, left_tag, label=label_string)   The left node is connected to its parent
                print_node(node.left, left_tag)

            if node.right is not None:
                right_tag = str(uuid.uuid1())
                self.dot.node(right_tag, str(node.right.data), style='filled', color=color)
                label_string = 'R' if label else ' '  # Whether to label the connection line to indicate the right subtree
                self.dot.edge(node_tag, right_tag, label=label_string)
                print_node(node.right, right_tag)

        # if the tree is not empty
        if self.data is not None:
            root_tag = str(uuid.uuid1())                # root node tag
            self.dot.node(root_tag, str(self.data), style='filled', color=sample(colors,1) [0])     Create the root node
            print_node(self, root_tag)

        self.dot.render(save_path)                              Save the file as the specified file
Copy the code
In the above code, create binary tree class BTree, implement the following methods: 1. Initialization method: The tree stores data. The left subtree and the right subtree are left and right. The default value is None. 1. Preorder () method: recursively achieve the sequential traversal of the binary tree; 1. Inorder () method: recursive realization of middle order traversal of binary tree; 1. Postorder () method: recursively achieve the post-order traversal of the binary tree; 1. Levelorder () method: recursive implementation of binary tree sequence traversal; 1. Height () method: calculate the height of binary tree; 1. Leaves () method: calculate the binary tree leaves; 1. Print_tree () method: Use Graphviz to realize binary tree visualization. The parameters to be set are save_path and label. Save_path is the file saving path. Label is the label that determines whether to add the left and right subtrees of the binary tree to the Graphviz file. It is used to tell which subtree is the left and which is the right subtree. It can be set by the user.Copy the code