Java data structure: What is a tree? how to use?


1. Tree

1 Overview

  • Unlike the one-to-one linear relationship represented by the linear table, the tree represents the non-linear relationship between more complex data elements .
  • Intuitively, the hierarchy tree branch relationship is defined , is to-many relationship
  • Tree definitions : tree (Tree) n is a finite set of nodes (n> = 0)
  • There is one and only one root (Root)
  • When n>1, the remaining nodes can be divided into m (m>0) disjoint finite sets T1, T2,..., Tm, each of which is a tree itself, and is called the root the sub-tree .

The definition of tree itself is a recursive definition, that is, the concept of tree is used in the definition of tree

2. Some basic terms

  • Tree node : contains a data element and several branches pointing to its subtree
  • Degree : the number of subtrees owned by the node
  • The node with degree ** 0 is called leaf **, or ** terminal node **. Of the node is not 0 ** ** referred to as non-terminal nodes or branch nodes
  • Root of the subtree of the node, the node is called a child (Child), corresponding to the node is called the child's parent (parent)
  • Call each other between a parent of a child with brothers (sibling)
  • Node ancestor from the root node to which all nodes on the branch is.
  • Any one node in the subtree rooted at some node in the node are called descendants
  • Node -level (Level) is defined beginning from the root, the root of the first layer, the second child root layer, so
  • The maximum level of the tree is called a node of the tree depth (depth) or the height

Two, binary tree

1 Overview

  • Definition : added constraints on the general tree:

  • Each node up to two sub-tree, binary tree that is not present in greater than 2 nodes

  • Subtree about the order of the points

  • There are 5 forms :

The form of a binary tree

  • Full binary tree and complete binary tree (for the lowest level of full binary tree, delete nodes from right to left)

2. Important features

  • Binary tree, at most 2i-1 nodes in the i-th layer
  • A binary tree of depth k has at most 2k-1 nodes
  • Height (or depth) of K a complete binary tree having at least 2k-2 th leaf node
  • Nonempty binary tree leaf node points is equal to a degree of 2 number of nodes plus one, namely:n0 = n2 + 1

N1 of a complete binary tree can only be 0 or 1

  • For a binary tree of degree m , the node of degree 1 is n1, the node of degree 2 is n2,..., the number of nodes of degree m is nm, then the number of leaf nodes: n0 **= 1 + n2 ****+ 2n3****+…+ (m-1)nm**
  • A complete binary tree with n nodes, with a depth of log2n + 1
  • Numbering nature : a complete binary tree with n nodes (its depth is log2n + 1 ), and each node is numbered from top to bottom and from left to right (1~n) then: if i is the number of a node a :
  • If i is not equal to 1, then the number of the parent node of a is: ⌊ i/2 ⌋
  • If 2i ≤ n , then the left child number of a is 2i ; if ** 2i> n**, then a** has no left child**;
  • If ** 2i + 1 ≤ n**, then the right child number of a is ** 2i + 1**; if ** 2i + 1> n**, then a** has no right child**;

Three, the storage structure of the binary tree

1. Sequential storage

  • Using an array to store data elements
  • From the storage perspective, this sequential storage structure, only for complete binary tree

Because in the worst case, a single tree with a depth of k and only k nodes (there is no node with a degree of 2 in the tree) requires a one-dimensional array of length 2k-1 .

2. Chain storage

  • To list the relationship between the form of data storage elements and data elements.

Chain storage


Fourth, the traversal of the binary tree

1. Determine the binary tree by the traversal sequence

  • The first sequence and the sequence can be determined
  • A subsequent sequence and may be determined (but note sequence after the last of the root , the next is a right subtree root )
  • By the hierarchy and sequence can be determined

2. Estimate the binary tree based on the traverse sequence

  • Preamble traversal sequence and postorder traversal sequence identical tree: only the root node
  • Preamble traversal and inorder traversal same binary tree: all nodes not left subtree (the right branch of the tree single
  • Inorder traversal and postorder traversal of the same binary tree: all nodes not right subtree (left single branch of the tree)
  • Preamble traversal and postorder traversal of the opposite binary tree: no left subtree right subtree or not ( only one leaf node ) the height of which is equal to the number of nodes
  • Preamble traversal and inorder traversal opposite binary tree: all nodes not right subtree (left single branch of the tree)
  • Inorder traversal and postorder traversal of the opposite binary tree: all nodes not left subtree (right single branch of the tree)

3. Traverse and build code

  • The establishment of a binary tree
  • Depth-first traversal (pre-order, middle-order and post-order)
  • Breadth first traversal (first order, second order)
/* BitTree.java */

package com.java.tree;

import java.util.LinkedList;
import java.util.Queue;

/**
 * Created by Jaco.Young.
 * 2018-06-13 18:26
 */
public class BitTree {
    
    

    //代表由先序和中序唯一确定的树的根结点
    private TreeNode root;

    /**
     * 提供给外部调用的方法
     * 字符数组pre表示先序遍历序列,mid表示中序遍历序列
     */
    public void build(char[] pre, char[] mid){
    
    
        //将创建树的根结点赋值给 root
        root = buildTree(pre,0, pre.length-1, mid, 0, mid.length-1);
    }

    /**
     * 前提条件,树中不存在重复元素
     * 由先序遍历序列和中序遍历序列,构造二叉树的方法
     * 我们建树的过程总是将序列不断地分割成左子树、右子树
     * lPre、rPre和lMid、rMid,分别就表示要对先序和中序的哪一部分进行建树
     */
    private TreeNode buildTree(char[] pre, int lPre, int rPre, char[] mid, int lMid, int rMid){
    
    
        //在先序遍历序列中,找到当前这棵树的根结点
        char root = pre[lPre];

        //在中序遍历序列中,根据先序中的根结点来查找在中序中的位置
        int rootIndex = getRootIndex(mid, lMid, rMid, root);

        //如果没有找到,说明所给的参数异常
        if(rootIndex == -1){
    
    
            throw new IllegalArgumentException("Illegal Argument!");
        }

        //计算当前这棵树,左右子树的个数
        //整个中序序列:[左子树(lMid)  root(rootIndex)  右子树(rMid)]
        //左子树[lMid,rootIndex-1]
        int lNum = rootIndex - lMid; //rootIndex-1 -lMid + 1
        //右子树[rootIndex+1,rMid]
        int rNum = rMid - rootIndex;  //rMid - (rootIndex + 1) + 1

        //开始构建当前根结点的左子树和右子树
        //先构建左子树
        TreeNode lchild;  //作为左子树的根结点
        //以当前结点为根的树,没有左子树
        if(lNum == 0){
    
    
            lchild = null;
        }else{
    
    
            //当前这个树的左子树,仍然是一棵树,递归构造这棵树的左子树
            //设x为当前树先序中左子树最后一个元素的下标,则:x - (lpre + 1) = lNum
            //得:x = lPre + lNum
            lchild = buildTree(pre, lPre + 1, lPre+lNum, mid, lMid, rootIndex - 1);
        }

        //构建右子树
        TreeNode rchild;
        if(rNum == 0){
    
    
            rchild = null;
        }else{
    
    
            //当前结点的右子树,仍然包含很多节点,需要递归的构造其右子树
            rchild = buildTree(pre, lPre + lNum + 1, rPre, mid, rootIndex + 1, rMid);
        }

        //构造完整的二叉树
        return new TreeNode(root,lchild,rchild);
    }

    //在中序遍历序列中,根据先序中的根结点来查找在中序中的位置
    private int getRootIndex(char[] mid, int lMid, int rMid, char root) {
    
    
        for(int i = lMid; i <= rMid; i++){
    
    
            if(mid[i] == root){
    
    
                return i;
            }
        }
        return -1;
    }

    //二叉树每一个结点的结构
    private class TreeNode{
    
    
        //结点中存储的数据
        char item;
        //指向左孩子结点
        TreeNode lChild;
        //指向右孩子结点
        TreeNode rChild;

        //构造方法,完成初始化
        public TreeNode(char item, TreeNode lChild, TreeNode rChild){
    
    
            this.item = item;
            this.lChild = lChild;
            this.rChild = rChild;
        }
    }

    //提供三个让外界调用的方法
    public  void preTraverse() {
    
    
        preOrder(root);
    }

    public void midTraverse() {
    
    
        midOrder(root);
    }

    public void postTraverse() {
    
    
        postOrder(root);
    }

    //先序遍历  DLR
    private void preOrder(TreeNode root) {
    
    
        if( root != null) {
    
    
            //先访问根节点
            System.out.print(root.item + " ");
            //递归访问左子树
            preOrder(root.lChild);
            //递归访问右子树
            preOrder(root.rChild);
        }
    }

    //中序遍历   LDR
    private void midOrder(TreeNode root) {
    
    
        if(root != null) {
    
    
            //递归访问左子树
            midOrder(root.lChild);
            //访问根
            System.out.print(root.item + " ");
            //递归访问右子树
            midOrder(root.rChild);
        }
    }

    //后续遍历
    // LRD
    private void postOrder(TreeNode root) {
    
    
        if(root != null) {
    
    
            //递归访问左子树
            postOrder(root.lChild);
            //递归访问右子树
            postOrder(root.rChild);
            //访问根
            System.out.print(root.item + " ");
        }
    }

    //广度优先遍历  BFS
    public void BFS() {
    
    
        //创建一个能放TreeNode对象的队列
        Queue<TreeNode> queue = new LinkedList<>();
        //将树的根节点入队列
        queue.add(root);
        //循环执行广度优先遍历
        while(!queue.isEmpty()) {
    
    
            //将当前的队头元素出队列
            TreeNode node = queue.remove();
            //访问出队列的节点
            System.out.print(node.item + " ");

            //出队列的节点是否有左孩子,有则将其左孩子入队列
            if(node.lChild != null) {
    
    
                //有左孩子
                queue.add(node.lChild);
            }
            //出队列的节点是否有右孩子,如果右,将其右孩子如队列
            if(node.rChild != null) {
    
    
                queue.add(node.rChild);
            }
        }
    }
}

/* Test.java*/
package com.java.tree;

/**
 * 测试类
 * Created by Jaco.Young.
 * 2018-06-13 20:16
 */
public class Test {
    
    
    public static void main(String[] args){
    
    
        //构造先序遍历序列和中序遍历序列
        char[] pre = {
    
    'A','B','E', 'K', 'L', 'F', 'D', 'H', 'J'};
        char[] mid = {
    
    'K', 'E', 'L', 'B', 'F', 'A', 'H', 'D', 'J'};

        BitTree bitTree = new BitTree();
        //根据遍历序列构建二叉树
        bitTree.build(pre, mid);

        //先序遍历
        bitTree.preTraverse();
        System.out.println();
        //中序遍历
        bitTree.midTraverse();
        System.out.println();
        //后序遍历
        bitTree.postTraverse();
        System.out.println();
        //广度优先遍历
        bitTree.BFS();
    }
}

The running result is:
ABEKLFDHJ
KELBFAHDJ
KLEFBHJDA
ABDEFHJKL

Guess you like

Origin blog.csdn.net/Java_Caiyo/article/details/110751434