Data structure (III) - binary tree related operations

Foreword

Here, too, does not introduce concepts binary tree, after all, the basic data structure has been talked about a lot, not repeat them here. As for some balanced binary tree, a complete binary tree, red-black trees, B + trees and other related structures, this has a lot of blog presented here just tell us about some of the basic operations of a binary tree.

definition

This should be seen many times

/**
 * autor:liman
 * createtime:2020/2/6
 * comment:二叉树节点的实现
 */
public class TreeNode {

    public String value;
    public TreeNode left;
    public TreeNode right;

    public TreeNode(String value) {
        this.value = value;
    }
}

Traversal non-recursive

Recursion is very simple to achieve, estimated that many people will be here to introduce non-recursive traversal to achieve

Basic traversal operation is as follows: output look here schematically represented traversal operation

/**
 * 做遍历的操作。
 *
 * @param node
 */
public static void doTraverse(TreeNode node) {
    System.out.print(node.value + " ");
}

Preorder

/**
 * 非递归实现的先序遍历,这里用到了栈的操作
 * 
 * @param root
 */
public static void preOrderTraverse(TreeNode root) {
    if (root != null) {//如果根节点不为空
        Stack<TreeNode> stack = new Stack<>();//非递归要用到栈
        stack.push(root);
        while (!stack.isEmpty()) {
            TreeNode node = stack.pop();
            doTraverse(node);
            //先判断右子树,再判断左子树
            if (node.right != null) {//判断右子树,如果右子树不为空,入栈
                stack.push(node.right);
            }
            if (node.left != null) {//判断左子树,如果左子树不空,则入栈
                stack.push(node.left);
            }
        }
    }
}

Preorder

/**
 * 非递归实现中序遍历
 *
 * @param root
 */
public static void innerOrderTraverse(TreeNode root) {
    if (root != null) {
        Stack<TreeNode> stack = new Stack<>();
        //不断的入栈左子树,找到整个树中最左端的一个节点(中序遍历的头结点)
        while (!stack.isEmpty() || root != null) {
            if (root != null) {
                stack.push(root);
                root = root.left;
            } else {//如果节点的左子树为空了,则直接弹出,遍历,然后指向右子树。
                root = stack.pop();
                doTraverse(root);
                root = root.right;
            }
        }

    }
}

Subsequent traversal

/**
 * 非递归实现后序遍历,一个栈比较麻烦,两个栈相对简单
 *
 * @param root
 */
public static void postOrderTraverse(TreeNode root) {
    if (root != null) {
        Stack<TreeNode> stack1 = new Stack<>();
        Stack<TreeNode> stack2 = new Stack<>();//用于存放待遍历的元素
        stack1.push(root);
        while (!stack1.isEmpty()) {
            TreeNode pop = stack1.pop();
            stack2.push(pop);
            if (pop.left != null) {
                stack1.push(pop.left);
            }
            if (pop.right != null) {
                stack1.push(pop.right);
            }
        }
        while (!stack2.isEmpty()) {
            doTraverse(stack2.pop());
        }
    }
}

Traverse the level

/**
 * 层次遍历,非递归实现
 * 利用队列
 * @param root
 */
public static void levelOrderTraverse(TreeNode root) {
    if (root != null) {
        Queue<TreeNode> queue = new ArrayDeque<>();
        queue.offer(root);//root入队列
        while (!queue.isEmpty()) {
            //获取当前层次的节点个数
            int levelNum = queue.size();
            for (int i = 0; i < levelNum; i++) {
                TreeNode node = queue.poll();
                doTraverse(node);
                if (node.left != null) {//入队左子树
                    queue.offer(node.left);
                }

                if (node.right != null) {//入队右子树
                    queue.offer(node.right);
                }
            }
        }
    }
}

Depth (maximum depth and the minimum depth) calculated binary tree

Maximum depth

Recursive

Recursion maximum depth, the code is the most simple

/**
 * 递归计算最大深度
 *
 * @param root
 * @return
 */
public int maxDepth(TreeNode root) {
    if (root == null) {
        return 0;
    }
    int left = maxDepth(root.left);
    int right = maxDepth(root.right);
    return Math.max(left, right) + 1;//毕竟根节点还是要算一层高度的。
}

Non-recursive

/**
 * 非递归实现最大深度,要用到层序遍历
 *
 * @param root
 * @return
 */
public int maxDepthLevel(TreeNode root) {
    if (root == null) {
        return 0;
    }

    Queue<TreeNode> queue = new ArrayDeque<>();
    queue.offer(root);
    int level = 0;
    while (!queue.isEmpty()) {
        level++; //这里统计层高
        int levelNum = queue.size();
        for (int i = 0; i < levelNum; i++) {
            TreeNode node = queue.poll();
            if (node.left != null) {
                queue.offer(node.left);
            }

            if (node.right != null) {
                queue.offer(node.right);
            }
        }
    }
    return level;
}

The minimum depth

The minimum depth compared to the maximum depth, we want to determine the conditions will be more, if the tree is empty directly returns 0 if there is only one root node directly returns 1 if the left subtree is empty right subtree is not empty, the minimum depth to be calculated right subtree. If the right subtree is empty left subtree is not empty, you need to calculate the left subtree minimum depth .

Recursive

/**
 * 递归求树的最小深度,这里需要考虑的条件更多
 *
 * @param root
 * @return
 */
public int mixDepth(TreeNode root) {
    if (root == null) {//树为空
        return 0;
    }
    if (root.left == null && root.right == null) {//只有一个根节点
        return 1;
    }
    if (root.left == null && root.right != null) {//左子树为空,右子树不为空
        return mixDepth(root.right) + 1;
    }
    if (root.right == null && root.left != null) {//右子树为空,左子树不为空
        return mixDepth(root.left) + 1;
    }

    //这个就是左子树和右子树都不为空的情况
    int left = mixDepth(root.left);
    int right = mixDepth(root.right);
    return Math.min(left,right)+1;
}

Non-recursive

Sequence traversal time, the height of the first left and right subtrees are empty node encountered, it must be a minimum depth

public int mixDepthLevel(TreeNode root){
    if (root == null) {
        return 0;
    }

    Queue<TreeNode> queue = new ArrayDeque<>();
    queue.offer(root);
    int level = 0;
    while (!queue.isEmpty()) {
        level++;
        int levelNum = queue.size();
        for (int i = 0; i < levelNum; i++) {
            TreeNode node = queue.poll();
            //第一个左右子树均为空的节点的层高,必是最小深度
            if(node.left== null && node.right == null){
                return level;
            }
            if (node.left != null) {
                queue.offer(node.left);
            }

            if (node.right != null) {
                queue.offer(node.right);
            }
        }
    }
    return 0;
}

Two computing nodes nearest ancestor

/**
 * 递归实现两个节点最近的祖先
 * @param root
 * @param node01
 * @param node02
 * @return
 */
public TreeNode lowestCommoAncestor(TreeNode root, TreeNode node01, TreeNode node02) {

    //最近的公共祖先是root节点
    if (root == null || root == node01 || root == node02) {
        return root;
    }

    TreeNode left = lowestCommoAncestor(root.left, node01, node02);
    TreeNode right = lowestCommoAncestor(root.right, node01, node02);

    if (left != null && right != null) {//如果左右都不空,说明两边均能找到node01和node02,则公共节点只能root了
        return root;
    }

    //如果只有一个为空,则那个公共的祖先就是这个节点。
    return left != null ? left : right;
}

The constructed binary sequence and the sequence preorder

In fact, this data structure in contact with the relevant issues, nothing more than to find the root from the preorder traversal sequence, then left the root node in order sequences are left subtree of the node, the node in the right sequence order are right subtree of the node.

public TreeNode buildTree(int[] preOrder,int[] inOrder){
    if(preOrder == null || inOrder == null){
        return null;
    }
    HashMap<Integer,Integer> map = new HashMap<>();
    for(int i=0;i<inOrder.length;i++){
        map.put(inOrder[i],i);
    }
    return buildTree(preOrder,0,preOrder.length-1,inOrder,0,inOrder.length-1,map);
}

/**
 *  根据中序和先序遍历的数组构建一个二叉树
 * @param preOrder 先序序列数组
 * @param pStart	先序序列的起始位置
 * @param pEnd		先序序列的结束位置
 * @param inOrder	中序序列数组
 * @param iStart	中序序列的起始位置
 * @param iEnd		中序序列的结束位置
 * @param map		中序序列元素与索引位置的map,仅仅只是为了搜索方便
 * @return
 */
public TreeNode buildTree(int[] preOrder,int pStart,int pEnd,
                          int[] inOrder,int iStart,int iEnd,
                          HashMap<Integer,Integer> map){
    if(pStart>pEnd || iStart>iEnd){
        return null;
    }

    TreeNode head = new TreeNode(preOrder[pStart]);
    int index = map.get(preOrder[pStart]);//找到根节点在中序遍历中的位置
    head.left = buildTree(preOrder,pStart+1,pStart+index-iStart,inOrder,iStart,index-1,map);
    head.right = buildTree(preOrder,pStart+index-iStart+1,pEnd,inOrder,index+1,iEnd,map);
    return head;

}

There are many variables on the index, with a direct expression of this map (As for the complete tree structure, Tell me what you can about the conversion yourself, this is not difficult):

Here Insert Picture Description

to sum up

Some basic operations are summed up, in fact, been achieved before in C, but are not systems.

Published 129 original articles · won praise 37 · views 90000 +

Guess you like

Origin blog.csdn.net/liman65727/article/details/104222410