[data structure] tree and binary tree

The halfway up the mountain is very crowded, you have to go to the top of the mountain to see


Table of contents

1. tree

1.1 The concept of a tree

1.2 Characteristics of trees

1.3 The relationship of each node of the tree 

1.4 Tree Representation 

2. Binary tree 

2.1 The concept of binary tree 

2.2 Special Binary Trees

2.3 Properties of Binary Trees 

2.4 Binary tree storage 

2.5 Basic operation of binary tree

2.5.1 Determine whether the binary tree is empty 

2.5.2 Preorder traversal of binary tree

2.5.3 Inorder traversal of a binary tree

2.5.4 Post-order traversal of a binary tree

 2.5.5 Get the number of nodes in the binary tree

 2.5.6 Get the number of leaf nodes of the binary tree

2.5.7 Get the number of nodes in the specified layer of the binary tree 

2.5.8 Get the height of the binary tree

2.5.9 Detect whether an element whose value is value exists

2.5.10 Level order traversal of binary tree

 2.5.11 Determine whether a binary tree is a complete binary tree


1. tree

1.1 The concept of a tree

A tree is a non-linear data structure, which is a set of hierarchical relationships composed of n (n>=0) finite nodes. It is called a tree because it looks like an upside-down tree, which means it has the roots pointing up and the leaves pointing down. 

  • There is a special node, called the root node, the root node has no predecessor nodes, but can have successor nodes
  • All nodes except the root node have a unique predecessor, and all nodes can have 0 or more successor nodes
  • The tree is defined recursively

1.2 Characteristics of trees

  • subtree disjoint
  • Except for the root node, each node has one and only one parent node (the root node has no parent node)
  • A tree of N nodes with N-1 edges

When the tree does not meet the above characteristics of the tree, it is not a tree

1.3 The relationship of each node of the tree 

Degree of node: The number of subtrees contained in a node is called the degree of the node; as shown in the figure above: A is 6

Degree of the tree: In a tree, the degree of the largest node is called the degree of the tree; as shown above: the degree of the tree is 6

Leaf node or terminal node: a node with a degree of 0 is called a leaf node; as shown in the figure above: B, C, H, I... and other nodes are leaf nodes

Non-terminal nodes or branch nodes: nodes whose degree is not 0; as shown in the above figure: nodes such as D, E, F, G... are branch nodes

Parent node or parent node: If a node contains child nodes, this node is called the parent node of its child nodes; as shown above: A is the parent node of B

Child node or child node: the root node of the subtree contained in a node is called the child node of the node; as shown above: B is the child node of A

Brother nodes: nodes with the same parent node are called brother nodes; as shown above: B and C are brother nodes  

The level of nodes: starting from the definition of the root, the root is the first level, the child nodes of the root are the second level, and so on;

Tree height or depth: the maximum level of nodes in the tree; as shown above: the height of the tree is 4 

Ancestors of a node: all nodes on the branch from the root to the node; as shown in the figure above: A is the ancestor of all nodes

Descendants: Any node in the subtree rooted at a node is called a descendant of the node. As shown above: all nodes are descendants of A

Forest: A collection of m (m>0) disjoint trees is called a forest

1.4 Tree Representation 

The tree structure is more complicated than the linear table, and it is more troublesome to store and express. In practice, there are many ways to express the tree, such as: parent representation, child brother representation , child representation and so on. 

Here we briefly understand the representation of parents and siblings of children :

Parent representation: 

Parent representation: store the parent node (parent node) of each node in an array, and the root node directly stores -1 without a parent node, because the array does not have a -1 subscript

Child sibling notation: 

Child brother notation: each node has a data domain, a child domain, and a sibling domain. If a node has multiple child nodes, let its child domain point to the first child node, and its first child node follows the Its second child node is also a brother relationship, then the brother domain of the first child node points to the second child node, and the second child node is also a brother relationship with the third child node, so that the second child node A node's sibling field points to the third child node, and so on.

2. Binary tree 

2.1 The concept of binary tree 

Concept : A binary tree is a finite set of nodes, the set is either empty, or consists of a root node plus two binary trees, also known as the left subtree and the right subtree 

  • Each node has at most two subtrees (left and right subtrees), that is, there is no node with a degree greater than 2 in the binary tree. (degrees up to 2)
  • The subtrees of the binary tree are divided into left and right, and the order of the subtrees cannot be reversed.

Note: When the degree of each node of a tree is less than or equal to two, the tree is a binary tree. Also a binary tree when there are no nodes

Each node of the binary tree can only be the following situations: 

2.2 Special Binary Trees

Full binary tree: a binary tree, if the number of nodes in each layer reaches the maximum value, then this binary tree is a full binary tree. That is to say, if the number of layers of a binary tree is h, and the total number of nodes is (2^h) -1, then it is a full binary tree

Complete binary tree: The height of a binary tree is h, when its h-1 levels are full. The last layer is not full, but the last layer is continuous from left to right. Such a binary tree is a complete binary tree (a full binary tree is a special complete binary tree)

2.3 Properties of Binary Trees 

  • If the number of layers of the root node is specified as 1, then there are at most 2^(i-1) nodes  on the i-th layer of a non-empty binary tree
  • If the number of layers of the root node is specified as 1, then the maximum number of nodes in a binary tree with a depth of h is  (2^h)- 1 
  • For any binary tree, if the number of leaf nodes with degree 0 is n0, and the number of branch nodes with degree 2 is n2, then n0=n2+1
  • If the number of layers of the root node is specified as 1, the depth h of a full binary tree with n nodes is  h=log₂n+1
  • The depth h of a complete binary tree with n nodes is  h=log₂(n+1) rounded up
  • Store a complete binary tree in the array in order from top to bottom and from left to right. Except for the root node, which is the node with subscript 0, the parent nodes of other nodes are (subscript-1)/2 . The left child node of all nodes is subscript *2+1 , and the right child node is subscript *2+2

2.4 Binary tree storage 

Binary tree storage is usually divided into: sequential storage and chain storage 

  • Sequential storage: usually used for complete binary trees 
  • Linked storage: usually refer to other nodes through the left, right, and parent node domains of a node

Child representation : use two node fields to store the left and right child nodes of this node respectively 

//孩子表示法
public class Node {
    private int val;//数据
    private Node left;//左孩子
    private Node right;//右孩子
}

Child parent representation : use three node fields to store the left and right parent nodes of this node respectively

//孩子双亲表示法
public class Node {
    private int val;//数据
    private Node left;//左孩子
    private Node right;//右孩子
    private Node parent; // 当前节点的双亲节点
}

2.5 Basic operation of binary tree

First, let's write a class for basic operations on binary trees:

public class MyBinaryTree {

}

A binary tree is constructed from nodes, so you need to write an inner class in the MyBinaryTree class as a node class:

//树的节点
public class Node {
    private int val;//数据
    private Node left;//左孩子
    private Node right;//右孩子
    private Node(int val) {
        this.val = val;
    }

    @Override
    public String toString() {
        return "Node{" +
                "节点=" + val +
                ", 左子节点=" + left.val +
                ", 右子节点=" + right.val +
                '}';
    }
}

To perform basic operations on a binary tree, you first need to have a binary tree, so we first write a method in the MyBinaryTree class to create a fixed binary tree:

//构造一棵二叉树
public Node createBinaryTree() {
    Node node1 = new Node(1);
    Node node2 = new Node(2);
    Node node3 = new Node(3);
    Node node4 = new Node(4);
    Node node5 = new Node(5);
    Node node6 = new Node(6);
    node1.left = node2;
    node1.right = node3;
    node2.left = node4;
    node2.right = node5;
    node3.left = node6;

    return node1;
}

With a binary tree, we can complete the basic operations of the binary tree

2.5.1 Determine whether the binary tree is empty 

Directly judge whether the passed root node is null, if it is null, it is an empty tree, otherwise it is not an empty tree 

//判断二叉树是否为空
public boolean isEmpty(Node root) {
    return root == null;
}

2.5.2 Preorder traversal of binary tree

First of all, we have to call the isEmpty method to determine whether the passed node is empty. If it is empty, we cannot continue to traverse down and return directly. Print the passed node if it is not empty, and then traverse the left and right subtrees recursively 

  1. Determine whether the node is empty, the node is empty return
  2. Node is not empty print node value 
  3. recursive left node 
  4. recursive right node 
First print the value of the node, then recurse the left subtree, and finally recurse the right subtree
//前序遍历
public void preOrder(Node root) {
    if (isEmpty(root)) {
        return;
    }
    //节点不为空,打印val值
    System.out.print(root.val+" ");
    //访问左子树
    preOrder(root.left);
    //访问右子树
    preOrder(root.right);
}

2.5.3 Inorder traversal of a binary tree

First of all, we have to call the isEmpty method to determine whether the passed node is empty. If it is empty, we cannot continue to traverse down and return directly. If it is not empty, use recursive traversal to the left subtree, then print the value of the node, and then use recursive traversal to the right subtree

  1. Determine whether the node is empty, the node is empty return
  2. Node is not empty, recursive left node 
  3. print node value
  4. recursive right node 
First recurse the left subtree, then print the node value, and finally recurse the right subtree
//中序遍历
public void inOrder(Node root) {
    if (isEmpty(root)) {
        return;
    }
    //先访问左子树
    inOrder(root.left);
    //当左子树遍历完,返回时打印val值
    System.out.print(root.val+" ");
    //再访问右子树
    inOrder(root.right);
}

2.5.4 Post-order traversal of a binary tree

First of all, we have to call the isEmpty method to determine whether the passed node is empty. If it is empty, we cannot continue to traverse down and return directly. If it is not empty, use recursive traversal to the left subtree, then use recursive traversal to the right subtree, and then print the value of the node

  1. Determine whether the node is empty, the node is empty return
  2. Node is not empty, recursive left node 
  3. recursive right node 
  4. print node value
recursive left node, recursive right node, print node value
//后序遍历
public void postOrder(Node root) {
    if (isEmpty(root)) {
        return;
    }
    //先访问左子树
    inOrder(root.left);
    //再访问右子树
    inOrder(root.right);
    //当左子树和右子树都访问完后打印val
    System.out.print(root.val+" ");
}

 2.5.5 Get the number of nodes in the binary tree

First of all, we have to call the isEmpty method to determine whether the passed node is empty. If it is empty, there is no node and return 0 directly. If it is not empty, recurse the left subtree, and then recurse the right subtree. When the recursion returns null, the number of nodes in the left subtree + the number of nodes in the right subtree + the number of nodes in itself

The number of nodes in the left subtree + the number of nodes in the right subtree + the number of nodes in itself
// 获取树中节点的个数
public int size(Node root) {
    if(isEmpty(root)) {
        return 0;
    }
    //将遍历的左子树右子树加起来,然后再加上本身的一个节点
    return size(root.left) + size(root.right) + 1;
}

 2.5.6 Get the number of leaf nodes of the binary tree

First of all, we have to call the isEmpty method to determine whether the passed node is empty. If it is empty, there is no node and return 0 directly. If it is not empty, judge whether its left node and right node are empty, if it is empty, return 1, if not empty, recurse its left subtree and right subtree, and then put the leaves of its left subtree and right subtree The number of nodes can be added up

The number of leaf nodes in the left subtree + the number of leaf nodes in the right subtree
// 获取叶子节点的个数
public int getLeafNodeCount(Node root) {
    if (isEmpty(root)) {
        return 0;
    }
    //如果一个节点的左子树和右子树都为null,说明这个节点就是叶子节点
    if (root.left == null && root.right == null) {
        return 1;
    }
    //将返回的叶子节点加起来
    return getLeafNodeCount(root.left) + getLeafNodeCount(root.right);
}

2.5.7 Get the number of nodes in the specified layer of the binary tree 

First of all, we have to call the isEmpty method to determine whether the passed node is empty. If it is empty, there is no node and return 0 directly. If it is not empty, it will recurse to the kth layer. If the node in the kth layer is not empty, it will return 1. If it is empty, it will return 0. Just add up the number of returned nodes in the kth layer.

Recurse to the specified layer, if the k node is not empty, return 1, and add up the nodes of the specified layer in the left subtree and right subtree
// 获取第K层节点的个数
public int getKLevelNodeCount(Node root,int k) {
    if (isEmpty(root)) {
        return 0;
    }
    //当k=1时,就是我们要获取的第k层的节点个数
    if (k == 1) {
        return 1;
    }
    //递归到第k层
    return getKLevelNodeCount(root.left, k - 1)
            + getKLevelNodeCount(root.right, k - 1);
}

2.5.8 Get the height of the binary tree

First of all, we have to call the isEmpty method to determine whether the passed node is empty. If it is empty, there is no node and return 0 directly. If it is not empty, traverse its left subtree and right subtree, and then judge which one has more nodes in the left subtree or right subtree, and return the more subtrees plus this node to the upper layer

Recursively judge which of the left subtree and the right subtree has more nodes, and return the more subtrees plus this node to the upper layer
// 获取二叉树的高度
public int getHeight(Node root) {
    if (isEmpty(root)) {
        return 0;
    }
    //遍历左子树
    int left = getHeight(root.left);
    //遍历右子树
    int right = getHeight(root.right);
    //判断左子树和右子树谁的节点多,多的子树加上本节点返回给上一层
    return left >= right ? left+1 : right+1;
}

2.5.9 Detect whether an element whose value is value exists

First of all, we have to call the isEmpty method to determine whether the passed node is empty. If it is empty, there will be no node and return null directly. If it is not empty, judge whether the val value of this node is the value we are looking for. If it is, it does not need to recurse and return this node directly. If the entire tree has been traversed, it will return null if there is no such node.

If found, return this node directly, if not found, return null
// 检测值为value的元素是否存在
public Node find(Node root, int value) {
    if (isEmpty(root)) {
        return null;
    }
    //当元素存在直接返回这个元素的节点
    if (root.val == value) {
        return root;
    }
    //访问左子树
    Node nodeL = find(root.left,value);
    if (nodeL != null) {
        return nodeL;
    }
    //访问右子树
    Node nodeR = find(root.right,value);
    if (nodeR != null) {
        return nodeR;
    }
    //如果没有这个节点就返回null
    return null;
}

2.5.10 Level order traversal of binary tree

First of all, we have to call the isEmpty method to determine whether the passed node is empty. If it is empty, no node will be returned directly. Instantiate a queue if it is not empty (queue: first-in-first-out), put the node into the queue, enter the loop after judging that the queue is not empty, put an element from the queue into the temporary variable tmp, and then print the tmp node val value, if the left node of the tmp node is not empty, enter the queue, if the right node of the tmp node is not empty, enter the queue, and so on until the queue is empty and jump out of the loop

//层序遍历
public void levelOrder(Node root) {
    if(isEmpty(root)) {
        return;
    }
    //用队列存储节点
    Queue<Node> queue = new LinkedList<>();
    //将第一个节点放入队列中
    queue.offer(root);
    //当队列不为空,就进入循环
    while (!queue.isEmpty()) {
        //弹出队列的队头元素
        Node tmp = queue.poll();
        //打印队头元素的值
        System.out.print(tmp.val+" ");
        //如果弹出的这个元素的左节点不为空,就入队列
        if (!isEmpty(tmp.left)) {
            queue.offer(tmp.left);
        }
        //如果弹出的这个元素的右节点不为空,就入队列
        if (!isEmpty(tmp.right)) {
            queue.offer(tmp.right);
        }
    }
    System.out.println();
}

 2.5.11 Determine whether a binary tree is a complete binary tree

First of all, we have to call the isEmpty method to determine whether the passed node is empty, if it is empty, there is no node and return true directly. Instantiate a queue if it is not empty (queue: first in first out), put the node in the queue, enter the loop if the queue is not empty, take an element from the queue and put it into the temporary variable tmp, and judge the node in tmp Whether it is null, if the node of tmp is empty, take out the nodes in the queue one by one, and judge whether all the nodes are null, if one of the nodes is not null, then the binary tree is not completed, and false is returned directly. If the node in tmp is not null, enqueue the left and right nodes of this node. Returns true for a complete binary tree when the queue is empty and does not enter a loop

// 判断一棵树是不是完全二叉树
public boolean isCompleteTree(Node root) {
    if (isEmpty(root)) {
        return true;
    }
    //用队列存储节点
    Queue<Node> queue = new LinkedList<>();
    //将第一个节点放入队列中
    queue.offer(root);
    //队列不为空,进循环
    while (!queue.isEmpty()) {
        //弹出队列的队头节点
        Node tmp = queue.poll();
        /*
        判断弹出的节点是否为null,如果是则将队列中的节点挨个弹出,并判断弹出的节点是否都为null,
        如果有一个不为null则就不是完成二叉树,直接返回false.
        如果弹出的节点不为null,则将这个节点的左右节点都入队。
        当队列为空,不进入循环是则为完全二叉树返回true
         */
        if (tmp == null) {
            while (!queue.isEmpty()) {
                Node t = queue.poll();
                if (t != null) {
                    return false;
                }
            }
        } else {
            queue.offer(tmp.left);
            queue.offer(tmp.right);
        }
    }
    return true;
}

Guess you like

Origin blog.csdn.net/m0_66488562/article/details/127654611