JAVA 二叉树 常见操作合集(前中后序递归非递归遍历 层序遍历 求深度宽度 判断兄弟结点 堂兄弟节点)

今天复习了二叉树的相关操作,整理归纳如下。

二叉树结点定义

 //节点类
    private static class TreeNode{
        private int val = 0;
        private TreeNode left;
        private TreeNode right;

        public TreeNode(int val, TreeNode left, TreeNode right) {
            this.val = val;
            this.left = left;
            this.right = right;
        }

        public int getVal() {
            return val;
        }

        public void setVal(int val) {
            this.val = val;
        }

        public TreeNode getLeft() {
            return left;
        }

        public void setLeft(TreeNode left) {
            this.left = left;
        }

        public TreeNode getRight() {
            return right;
        }

        public void setRight(TreeNode right) {
            this.right = right;
        }
}

二叉树类定义


public class binaryTree {
    private TreeNode root;
    public binaryTree(){

    }
    public binaryTree(TreeNode root) {
        this.root = root;
    }

    public TreeNode getRoot() {
        return root;
    }

    public void setRoot(TreeNode root) {
        this.root = root;
    }
}

前序遍历 递归

    //前序遍历 递归
    public void preOrderRecursively(TreeNode node){
        if(node == null)
            return;
        System.out.print(node.val+"  ");
        preOrderRecursively(node.left);
        preOrderRecursively(node.right);
    }

前序遍历非递归:基本思路是利用栈,从根结点开始,先将根结点进栈,再根结点出栈,然后将根结点的右结点入栈,再左结点入栈。再重复以上循环 栈顶出栈-访问-右子节点入栈-左子节点入栈。

    //前序遍历 非递归
    public void preOrderNoRecursively(TreeNode node){
        Stack<TreeNode> st = new Stack<>();
        if(st != null)
            st.push(node);
        while (st.isEmpty() == false){
            TreeNode cur = st.pop();
            System.out.print(cur.getVal()+"  ");
            if(cur.getRight() != null)
                st.push(cur.getRight());
            if(cur.getLeft() != null)
                st.push(cur.getLeft());
        }

    }

中序遍历递归

    //中序遍历 递归
    public void inOrderRecursively(TreeNode node){
        if(node == null)
            return;
        inOrderRecursively(node.left);
        System.out.print(node.val + "  ");
        inOrderRecursively(node.right);
    }

中序遍历非递归:思路还是利用栈,先从根结点开始走到最左端结点,然后访问该结点,再查看是否存在右子节点,如果有,继续从右子节点朝左走。

    //中序遍历 非递归
    public void inOrderNoRecursively(TreeNode node){
        if(node == null)
            return;
        Stack<TreeNode> st = new Stack<>();
        TreeNode cur = node;
        while (cur!=null || st.isEmpty()==false){
            while (cur != null){
                st.push(cur);
                cur = cur.getLeft();
            }
            if(!st.isEmpty()){
                cur = st.pop();
                System.out.print(cur.getVal()+"  ");
                cur = cur.getRight();
            }
        }
    }

后序遍历递归:

    //后序遍历 递归
    public void postOrderRecursively(TreeNode node){
        if(node == null)
            return;
        postOrderRecursively(node.left);
        postOrderRecursively(node.right);
        System.out.print(node.getVal()+"  ");
    }

后序遍历非递归:一个较容易理解的方法是双栈法,即利用两个栈。因为后序遍历的顺序恰好是 先遍历右子树再遍历左子树的前序遍历的逆序

    //后序遍历 非递归 可以看作是 先遍历右子树再遍历左子树的前序遍历 的结果 的逆序
    public void postOrderNoRecursively(TreeNode node){
        if(node == null)
            return;
        Stack<TreeNode> st = new Stack<>();
        Stack<Integer> temp = new Stack<>();
        st.push(node);
        while (!st.isEmpty()) {
            TreeNode cur = st.pop();
            temp.push(cur.getVal());
            if (cur.getLeft() != null)
                st.push(cur.getLeft());
            if (cur.getRight() != null)
                st.push(cur.getRight());
        }
        while(!temp.isEmpty()){
            System.out.print(temp.pop()+"  ");
        }
    }

层序遍历 并且给出每个结点的深度

利用队列,先将根结点入队,再出队,把根结点的左右子树入队。

//层序遍历  并且给出每个结点的深度
    public void levelOrder(TreeNode node){
        if(node == null)
            return;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(node);
        int levelNum = 1;
        while (queue.size()!=0){
            int len = queue.size();
            for (int i = 0; i < len; i++) {
                TreeNode temp = queue.poll();

                System.out.print(temp.val+"  levelNum = "+levelNum+"  ");
                if(temp.getLeft() != null)
                    queue.add(temp.getLeft());
                if(temp.getRight() != null)
                    queue.add(temp.getRight());
            }
            levelNum++;
        }
    }

层序遍历的应用://求指定结点值的结点深度

 //求指定结点值的结点深度
    public int levelCount(TreeNode node,int x){
        if(node == null)
            return -1;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(node);
        int levelNum = 1;
        while (queue.size()!=0){
            int len = queue.size();
            for (int i = 0; i < len; i++) {
                TreeNode temp = queue.poll();
                if(temp.val == x)
                    return levelNum;
                if(temp.getLeft() != null)
                    queue.add(temp.getLeft());
                if(temp.getRight() != null)
                    queue.add(temp.getRight());
            }
            levelNum++;
        }
        return -1;
    }

判断两个节点是否为兄弟结点

//判断两个结点是否为兄弟结点  兄弟结点:父亲相同的结点
    public boolean isBrother(TreeNode node, int x, int y){//x和y为待判断结点
        if(node == null)
            return false;
        if(node.left != null && node.right != null){
            if((node.left.val == x && node.right.val == y) || (node.left.val == y && node.right.val == x)){
                return true;
            }
        }
        if(isBrother(node.left,x,y))
            return true;
        if(isBrother(node.right,x,y))
            return true;
        return false;
    }

判断两个节点是否为堂兄弟结点:堂兄弟结点 深度相同但不是同一个父结点的孩子

    //判断两个节点是否为堂兄弟结点:堂兄弟结点  深度相同但不是同一个父结点的孩子
    public boolean isCousin(TreeNode node, int x, int y){
        if(node == null)
            return false;
        if(levelCount(node, x) != levelCount(node,y))
            return false;
        else{
            if(isBrother(node, x, y))
                return false;
            else
                return true;
        }
    }

递归求树的深度

    //求树的深度
    public int getDepth(TreeNode node){
        if(node == null)
            return 0;
        else {
            int hl = getDepth(node.left);
            int hr = getDepth(node.right);
            return (hr > hr ? hr  : hl )+1;
        }
    }

利用层序遍历求树的宽度

//获取二叉树的宽度
    public int getWidth(TreeNode node){
        if(node == null)
            return 0;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(node);
        int maxWidth = 1;
        while (queue.size()!=0){
            int len = queue.size();
            for (int i = 0; i < len; i++) {
                TreeNode temp = queue.poll();

                if(temp.getLeft() != null)
                    queue.add(temp.getLeft());
                if(temp.getRight() != null)
                    queue.add(temp.getRight());
            }
            if(len > maxWidth)
                maxWidth = len;
        }
        return maxWidth;
    }

利用前序和中序序列重建二叉树

例如前序序列{1,2,4,7,3,5,6,8}

中序序列{4,7,2,1,5,3,8,6}

前序序列的第一个数字1是根结点的值,扫描中序序列,位于1前面的{4,7,2}为左子树节点的值,位于1后面的{5.3.8.6}为右子树节点的值,

现在我们对于前半部分 前序{2,4,7}和中序{4,7,2}继续进行以上步骤。

同理采用递归的思路,我们可以完成此题。

//利用前序和中序序列重建二叉树
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
    if(pre.length == 0 || in.length == 0)
        return null;
    int len = pre.length-1;
    return reConstructBinaryTreeCore(pre,0,len,in,0,len);
}
public TreeNode reConstructBinaryTreeCore(int [] pre, int preStart,int preEnd,int [] in,int inStart,int inEnd){
     int rootValue = pre[preStart];
    TreeNode root = new TreeNode(rootValue,null,null);
    root.left = null;
    root.right = null;
    if(preStart > preEnd || inStart > inEnd)
        return null;
    if(preStart == preEnd){
        if(inStart == inEnd && pre[preStart]==in[inStart])
            return root;
        else
            return null;
    }
    int rootInOrder = inStart;
    for (int i = inStart; i <= inEnd; i++) {
        if(in[i] == rootValue){
            rootInOrder = i;
            break;
        }
    }
    int leftLength = rootInOrder - inStart ;
    int leftPreOrderEnd = preStart + leftLength ;
    if(leftLength > 0){
        root.left = reConstructBinaryTreeCore(pre,preStart+1,leftPreOrderEnd,in,inStart,rootInOrder-1);
    }
    if(leftLength < preEnd - preStart){
        root.right = reConstructBinaryTreeCore(pre,leftPreOrderEnd+1,preEnd,in,rootInOrder+1,inEnd);
    }
    return root;
}

完整源程序如下:

/*
 * Created by maomao (c)
 * 2019. 2. 21.
 * at Xi'an jiaotong university.
 */

package DS.binaryTree;

import sun.reflect.generics.tree.Tree;

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

public class binaryTree {
    private TreeNode root;
    public binaryTree(){

    }
    public binaryTree(TreeNode root) {
        this.root = root;
    }

    public TreeNode getRoot() {
        return root;
    }

    public void setRoot(TreeNode root) {
        this.root = root;
    }

    //节点类
    private static class TreeNode{
        private int val = 0;
        private TreeNode left;
        private TreeNode right;

        public TreeNode(int val, TreeNode left, TreeNode right) {
            this.val = val;
            this.left = left;
            this.right = right;
        }

        public int getVal() {
            return val;
        }

        public void setVal(int val) {
            this.val = val;
        }

        public TreeNode getLeft() {
            return left;
        }

        public void setLeft(TreeNode left) {
            this.left = left;
        }

        public TreeNode getRight() {
            return right;
        }

        public void setRight(TreeNode right) {
            this.right = right;
        }
    }
    //前序遍历 递归
    public void preOrderRecursively(TreeNode node){
        if(node == null)
            return;
        System.out.print(node.val+"  ");
        preOrderRecursively(node.left);
        preOrderRecursively(node.right);
    }
    //前序遍历 非递归
    public void preOrderNoRecursively(TreeNode node){
        Stack<TreeNode> st = new Stack<>();
        if(st != null)
            st.push(node);
        while (st.isEmpty() == false){
            TreeNode cur = st.pop();
            System.out.print(cur.getVal()+"  ");
            if(cur.getRight() != null)
                st.push(cur.getRight());
            if(cur.getLeft() != null)
                st.push(cur.getLeft());
        }

    }
    //中序遍历 递归
    public void inOrderRecursively(TreeNode node){
        if(node == null)
            return;
        inOrderRecursively(node.left);
        System.out.print(node.val + "  ");
        inOrderRecursively(node.right);
    }
    //中序遍历 非递归
    public void inOrderNoRecursively(TreeNode node){
        if(node == null)
            return;
        Stack<TreeNode> st = new Stack<>();
        TreeNode cur = node;
        while (cur!=null || st.isEmpty()==false){
            while (cur != null){
                st.push(cur);
                cur = cur.getLeft();
            }
            if(!st.isEmpty()){
                cur = st.pop();
                System.out.print(cur.getVal()+"  ");
                cur = cur.getRight();
            }
        }
    }
    //后序遍历 递归
    public void postOrderRecursively(TreeNode node){
        if(node == null)
            return;
        postOrderRecursively(node.left);
        postOrderRecursively(node.right);
        System.out.print(node.getVal()+"  ");
    }
    //后序遍历 非递归 可以看作是 先遍历右子树再遍历左子树的前序遍历 的结果 的逆序
    public void postOrderNoRecursively(TreeNode node){
        if(node == null)
            return;
        Stack<TreeNode> st = new Stack<>();
        Stack<Integer> temp = new Stack<>();
        st.push(node);
        while (!st.isEmpty()) {
            TreeNode cur = st.pop();
            temp.push(cur.getVal());
            if (cur.getLeft() != null)
                st.push(cur.getLeft());
            if (cur.getRight() != null)
                st.push(cur.getRight());
        }
        while(!temp.isEmpty()){
            System.out.print(temp.pop()+"  ");
        }
    }

    //层序遍历  并且给出每个结点的深度
    public void levelOrder(TreeNode node){
        if(node == null)
            return;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(node);
        int levelNum = 1;
        while (queue.size()!=0){
            int len = queue.size();
            for (int i = 0; i < len; i++) {
                TreeNode temp = queue.poll();

                System.out.print(temp.val+"  levelNum = "+levelNum+"  ");
                if(temp.getLeft() != null)
                    queue.add(temp.getLeft());
                if(temp.getRight() != null)
                    queue.add(temp.getRight());
            }
            levelNum++;
        }
    }
    //求指定结点值的结点深度
    public int levelCount(TreeNode node,int x){
        if(node == null)
            return -1;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(node);
        int levelNum = 1;
        while (queue.size()!=0){
            int len = queue.size();
            for (int i = 0; i < len; i++) {
                TreeNode temp = queue.poll();
                if(temp.val == x)
                    return levelNum;
                if(temp.getLeft() != null)
                    queue.add(temp.getLeft());
                if(temp.getRight() != null)
                    queue.add(temp.getRight());
            }
            levelNum++;
        }
        return -1;
    }
    //判断两个结点是否为兄弟结点  兄弟结点:父亲相同的结点
    public boolean isBrother(TreeNode node, int x, int y){//x和y为待判断结点
        if(node == null)
            return false;
        if(node.left != null && node.right != null){
            if((node.left.val == x && node.right.val == y) || (node.left.val == y && node.right.val == x)){
                return true;
            }
        }
        if(isBrother(node.left,x,y))
            return true;
        if(isBrother(node.right,x,y))
            return true;
        return false;
    }
    //判断两个节点是否为堂兄弟结点:堂兄弟结点  深度相同但不是同一个父结点的孩子
    public boolean isCousin(TreeNode node, int x, int y){
        if(node == null)
            return false;
        if(levelCount(node, x) != levelCount(node,y))
            return false;
        else{
            if(isBrother(node, x, y))
                return false;
            else
                return true;
        }
    }
    //求树的深度
    public int getDepth(TreeNode node){
        if(node == null)
            return 0;
        else {
            int hl = getDepth(node.left);
            int hr = getDepth(node.right);
            return (hr > hr ? hr  : hl )+1;
        }
    }
    //获取二叉树的宽度
    public int getWidth(TreeNode node){
        if(node == null)
            return 0;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(node);
        int maxWidth = 1;
        while (queue.size()!=0){
            int len = queue.size();
            for (int i = 0; i < len; i++) {
                TreeNode temp = queue.poll();

                if(temp.getLeft() != null)
                    queue.add(temp.getLeft());
                if(temp.getRight() != null)
                    queue.add(temp.getRight());
            }
            if(len > maxWidth)
                maxWidth = len;
        }
        return maxWidth;
    }
    //利用前序和中序序列重建二叉树
    public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
        if(pre.length == 0 || in.length == 0)
            return null;
        int len = pre.length-1;
        return reConstructBinaryTreeCore(pre,0,len,in,0,len);
    }
    public TreeNode reConstructBinaryTreeCore(int [] pre, int preStart,int preEnd,int [] in,int inStart,int inEnd){
        int rootValue = pre[preStart];
        TreeNode root = new TreeNode(rootValue,null,null);
        root.left = null;
        root.right = null;
        if(preStart > preEnd || inStart > inEnd)
            return null;
        if(preStart == preEnd){
            if(inStart == inEnd && pre[preStart]==in[inStart])
                return root;
            else
                return null;
        }
        int rootInOrder = inStart;
        for (int i = inStart; i <= inEnd; i++) {
            if(in[i] == rootValue){
                rootInOrder = i;
                break;
            }
        }
        int leftLength = rootInOrder - inStart ;
        int leftPreOrderEnd = preStart + leftLength ;
        if(leftLength > 0){
            root.left = reConstructBinaryTreeCore(pre,preStart+1,leftPreOrderEnd,in,inStart,rootInOrder-1);
        }
        if(leftLength < preEnd - preStart){
            root.right = reConstructBinaryTreeCore(pre,leftPreOrderEnd+1,preEnd,in,rootInOrder+1,inEnd);
        }
        return root;
    }
    public static void main(String[] args) {
        TreeNode l2 = new TreeNode(5, null, null);//这五行构造一棵二叉树
        TreeNode r2 = new TreeNode(4, null, null);
        TreeNode l1 = new TreeNode(3,null, r2);// 根节点左子树
        TreeNode r1 = new TreeNode(2, l2, null);// 根节点右子树
        TreeNode root = new TreeNode(1, l1, r1);// 创建根节点

        binaryTree bt = new binaryTree(root);
        System.out.println(" 递归 前序遍历------->");
        bt.preOrderRecursively(bt.getRoot());
        System.out.println();
        System.out.println(" 非递归 前序遍历------->");
        bt.preOrderNoRecursively(bt.getRoot());
        System.out.println();
        System.out.println(" 递归 中序遍历------->");
        bt.inOrderRecursively(bt.getRoot());
        System.out.println();
        System.out.println(" 非递归 中序遍历------->");
        bt.inOrderNoRecursively(bt.getRoot());
        System.out.println();
        System.out.println(" 递归 后序遍历------->");
        bt.postOrderRecursively(bt.getRoot());
        System.out.println();
        System.out.println(" 非递归 后序遍历------->");
        bt.postOrderNoRecursively(bt.getRoot());
        System.out.println();
        System.out.println(" 层序遍历------->");
        bt.levelOrder(bt.getRoot());
        System.out.println();
        System.out.println(" 求指定结点值的深度------->");
        int target = 5;
        int resIndex = bt.levelCount(bt.getRoot(),5);
        System.out.println("resIndex = "+resIndex+" ");
        System.out.println(" 判断两个结点是否为兄弟结点------->");
        if(bt.isBrother(bt.getRoot(),l1.getVal(),r1.getVal()))
            System.out.println("是兄弟结点");
        else
            System.out.println("不是兄弟结点");
        System.out.println(" 判断两个结点是否为堂兄弟结点------->");
        if(bt.isCousin(bt.getRoot(),l2.getVal(),r2.getVal()))
            System.out.println("是堂兄弟结点");
        else
            System.out.println("不是堂兄弟结点");
        System.out.println(" 求二叉树的深度------->");
        System.out.println(bt.getDepth(bt.getRoot()));
        System.out.println(" 求二叉树的宽度------->");
        System.out.println(bt.getWidth(bt.getRoot()));
        System.out.println(" 利用前序和中序序列重建二叉树------->");
//        int[] pre = {1,2,4,7,3,5,6,8};
//        int[] in = {4,7,2,1,5,3,8,6};
        int[] pre = {1,2,4,3};
        int[] in = {4,2,1,3};
        TreeNode newTree = bt.reConstructBinaryTree(pre,in);
        bt.preOrderRecursively(newTree);
    }
}

 

猜你喜欢

转载自blog.csdn.net/qq_25406563/article/details/87859008