后中序遍历推层次遍历(华为od机考题)

一、题目

1.原题

有一棵二叉树,每个节点由一个大写字母标识(最多26个节点)。
现有两组字母,
分别表示后序遍历(左孩子->右孩子->父节点)和                                                                          中序遍历(左孩子->父节点->右孩子)的结果,
请输出层次遍历的结果。

2.题目理解

已知一棵二叉树的后序遍历和中序遍历结果,可以根据两种遍历结果重建二叉树,再进行层次遍历(广度优先遍历)。

二、思路与代码过程

1.思路

二叉树的后序遍历(左子树->右子树->根节点)的最后一个元素是根节点;中序遍历(左子树->根节点->右子树)的中间是根节点;由后序遍历可得到根节点的值,再在中序遍历中查找到位置,就可分出左子树和右子树(左子树和右子树同理)。

创建一个分割函数(接收传值:左右子树值链表和当前根节点值),递归调用它分割左右子树,并对二叉树进行构建(第一个根节点传入后有了root,分割出左右子树后序遍历后可以从末尾获取左右子树的节点值,有了root->left和root->right,递归下去直到左右子树链表为空)。

最后对root进行层次遍历打印即可。

2.代码过程

①main函数

public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        ArrayList<String> postorderTraversal = new ArrayList<>();
        ArrayList<String> inorderTraversal = new ArrayList<>();
        System.out.println("请输入当前二叉树后序遍历的结果:");
        String[] sb = sc.nextLine().split(" ");
        for (String s : sb) {
            postorderTraversal.add(s);
        }
        System.out.println("请输入当前二叉树中序遍历的结果:");
        String[] sm = sc.nextLine().split(" ");
        for (String s : sm) {
            inorderTraversal.add(s);
        }
        TreeNode BFSresult = OutPutBFS(postorderTraversal,inorderTraversal);
        System.out.print("该二叉树的层次遍历结果为:");
        BFSresult.printLevelOrder();
    }

②OutPutBFS函数

private static TreeNode OutPutBFS(ArrayList<String> postorderTraversal, ArrayList<String> inorderTraversal) {
        int n = postorderTraversal.size();
        TreeNode FristNode = new TreeNode(postorderTraversal.get(n-1));
        TreeNode root = splitLRSubTree(postorderTraversal,inorderTraversal,FristNode);
        return root;
    }

③全局变量

static ArrayList<TreeNode> rootNode = new ArrayList<>();

④splitLRSubTree函数

private static TreeNode splitLRSubTree(ArrayList<String> postorderTraversal, ArrayList<String> inorderTraversal,TreeNode root) {
        int n = postorderTraversal.size();//
        ArrayList<String> leftSubTreePT = new ArrayList<>();
        ArrayList<String> rightSubTreePT = new ArrayList<>();
        ArrayList<String> leftSubTreeIT = new ArrayList<>();
        ArrayList<String> rightSubTreeIT = new ArrayList<>();
            for (int i = 0; i < postorderTraversal.size(); i++) {
                //后序遍历的最后一个是根节点,遍历中序找到后序的最后一个节点值的位置
                if (inorderTraversal.get(i).equals(postorderTraversal.get(n - 1))) {
                    //将根节点加入根节点链表
                    rootNode.add(root);
                    break;
                } else {
                    //没找到时,后序遍历左子树添加后序遍历的数值
                    leftSubTreePT.add(postorderTraversal.get(i));
                    //中序遍历添加中序遍历的数值
                    leftSubTreeIT.add(inorderTraversal.get(i));
                }
            }
            //从链表的最后开始转存入
            for (int i = leftSubTreePT.size(); i<n-1; i++) {
                rightSubTreePT.add(postorderTraversal.get(i));
                rightSubTreeIT.add(inorderTraversal.get(i + 1));
            }
        //左节点加入方法
        //左子树的长度不为零,将左子树的后序遍历的末尾作为当前root的左节点
        if (leftSubTreePT.size()>0) {
            int leftSize = leftSubTreePT.size();
            TreeNode LeftNode = new TreeNode(leftSubTreePT.get(leftSize-1));
            root.left = LeftNode;
        }
        //右节点加入方法
        //右子树的长度不为零,将右子树的后序遍历的末尾作为当前root的左节点
        if (rightSubTreePT.size()>0) {
            int rightSize = rightSubTreePT.size();
            TreeNode RightNode = new TreeNode(rightSubTreePT.get(rightSize-1));
            root.right = RightNode;
        }

            //递归
        if (leftSubTreePT.size()>1) {
            splitLRSubTree(leftSubTreePT,leftSubTreeIT,root.left);//DEB DBE
        }
        if (rightSubTreePT.size()>1) {
            splitLRSubTree(rightSubTreePT,rightSubTreeIT,root.right);//FC CF
        }
        //若树节点数等于所有节点数,返回
        if (root.countNodes()==n) {
            return root;
        }
        return root;
    }

⑤TreeNode类

static class TreeNode{
        String value;
        TreeNode left;
        TreeNode right;

        TreeNode(String value){
            this.value = value;
            this.left = null;
            this.right = null;
        }
        public int countNodes() {
            if (this == null) {
                return 0;
            }
            return 1 + (left != null ? left.countNodes() : 0) + (right != null ? right.countNodes() : 0);
        }

        public void printLevelOrder() {
            if (this == null) {
                return;
            }
            Queue<TreeNode> queue = new LinkedList<>();
            queue.add(this);
            StringBuilder result = new StringBuilder();
            while (!queue.isEmpty()) {
                TreeNode node = queue.poll();
                result.append(node.value).append(" "); // 将节点值添加到结果中,并用空格分隔
                if (node.left != null) {
                    queue.add(node.left);
                }
                if (node.right != null) {
                    queue.add(node.right);
                }
            }
            System.out.println(result.toString().trim()); // 打印整个结果,并去除末尾的多余空格
        }

        public String toString(){
            return value;
        }
    }

三、运行结果

1.运行截图

2.带数据分析运行结果

-------splitLRSubTree开始-------
中序子树[D, B, E, A, C, F]
后序子树[D, E, B, F, C, A]
1 根节点:
A
1 根节点:
A
1 中序子树[D, B, E, A, C, F]
1 后序子树[D, E, B, F, C, A]
-------循环开始-------
中序i=0,值为D
后序i=0,值为D
根节点值为:A
未找到根节点将D加入中序左子树leftSubTreeIT
未找到根节点将D加入后序左子树leftSubTreePT
2 中序左子树[D]
2 后序左子树[D]
-------循环开始-------
中序i=1,值为B
后序i=1,值为E
根节点值为:A
未找到根节点将B加入中序左子树leftSubTreeIT
未找到根节点将E加入后序左子树leftSubTreePT
2 中序左子树[D, B]
2 后序左子树[D, E]
-------循环开始-------
中序i=2,值为E
后序i=2,值为B
根节点值为:A
未找到根节点将E加入中序左子树leftSubTreeIT
未找到根节点将B加入后序左子树leftSubTreePT
2 中序左子树[D, B, E]
2 后序左子树[D, E, B]
-------循环开始-------
中序i=3,值为A
后序i=3,值为F
根节点值为:A
找到了根节点:A
当前根节点链表为[A]
2 中序右子树[C]
2 后序右子树[F]
2 中序右子树[C, F]
2 后序右子树[F, C]
-------分割后检查-------
3 根节点:
A
3 中序左子树[D, B, E]
3 后序左子树[D, E, B]
3 中序右子树[C, F]
3 后序右子树[F, C]
----------递归开始---------
-------splitLRSubTree开始-------
中序子树[D, B, E]
后序子树[D, E, B]
1 根节点:
B
1 根节点:
B
1 中序子树[D, B, E]
1 后序子树[D, E, B]
-------循环开始-------
中序i=0,值为D
后序i=0,值为D
根节点值为:B
未找到根节点将D加入中序左子树leftSubTreeIT
未找到根节点将D加入后序左子树leftSubTreePT
2 中序左子树[D]
2 后序左子树[D]
-------循环开始-------
中序i=1,值为B
后序i=1,值为E
根节点值为:B
找到了根节点:B
当前根节点链表为[A, B]
2 中序右子树[E]
2 后序右子树[E]
-------分割后检查-------
3 根节点:
B
3 中序左子树[D]
3 后序左子树[D]
3 中序右子树[E]
3 后序右子树[E]
----------递归开始---------
当前二叉树的层次遍历为:B D E
根节点链表长度为:3
-------splitLRSubTree开始-------
中序子树[C, F]
后序子树[F, C]
1 根节点:
C
1 根节点:
C
1 中序子树[C, F]
1 后序子树[F, C]
-------循环开始-------
中序i=0,值为C
后序i=0,值为F
根节点值为:C
找到了根节点:C
当前根节点链表为[A, B, C]
2 中序右子树[F]
2 后序右子树[F]
-------分割后检查-------
3 根节点:
C
3 中序左子树[]
3 后序左子树[]
3 中序右子树[F]
3 后序右子树[F]
----------递归开始---------
当前二叉树的层次遍历为:C F
根节点链表长度为:2
当前二叉树的层次遍历为:A B C D E F
根节点链表长度为:6
该二叉树的层次遍历结果为:A B C D E F

3.带数据分析完整代码

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

public class test26 {
    public static void main(String[] args) {
       /*
        Scanner sc = new Scanner(System.in);
        ArrayList<String> postorderTraversal = new ArrayList<>();
        ArrayList<String> inorderTraversal = new ArrayList<>();
        System.out.println("请输入当前二叉树后序遍历的结果:");
        String[] sb = sc.nextLine().split(" ");
        for (String s : sb) {
            postorderTraversal.add(s);
        }
        System.out.println("请输入当前二叉树中序遍历的结果:");
        String[] sm = sc.nextLine().split(" ");
        for (String s : sm) {
            inorderTraversal.add(s);
        }
        System.out.println("当前二叉树层次遍历的结果为:");
        */
        // /*测试
        int n = 6;
        String[] sb = {"D", "E", "B", "F", "C", "A"};//后
        String[] sm = {"D", "B", "E", "A", "C", "F"};//中
        ArrayList<String> postorderTraversal = new ArrayList<>();
        ArrayList<String> inorderTraversal = new ArrayList<>();
        for (String s : sb) {
            postorderTraversal.add(s);
        }
        for (String s : sm) {
            inorderTraversal.add(s);
        }
        //层次遍历:ABCDEF
        TreeNode BFSresult = OutPutBFS(postorderTraversal,inorderTraversal);
        System.out.print("该二叉树的层次遍历结果为:");
        BFSresult.printLevelOrder();
    }

    private static TreeNode OutPutBFS(ArrayList<String> postorderTraversal, ArrayList<String> inorderTraversal) {
        int n = postorderTraversal.size();//
        TreeNode FristNode = new TreeNode(postorderTraversal.get(n-1));
        TreeNode root = splitLRSubTree(postorderTraversal,inorderTraversal,FristNode);
        return root;
    }
    
    static ArrayList<TreeNode> rootNode = new ArrayList<>();
    private static TreeNode splitLRSubTree(ArrayList<String> postorderTraversal, ArrayList<String> inorderTraversal,TreeNode root) {
        System.out.println("-------splitLRSubTree开始-------");
        System.out.println("中序子树"+inorderTraversal);//FC
        System.out.println("后序子树"+postorderTraversal);//DEB
        System.out.println("1 根节点:");// A
        root.printLevelOrder();

        int n = postorderTraversal.size();//
        ArrayList<String> leftSubTreePT = new ArrayList<>();
        ArrayList<String> rightSubTreePT = new ArrayList<>();
        ArrayList<String> leftSubTreeIT = new ArrayList<>();
        ArrayList<String> rightSubTreeIT = new ArrayList<>();

        System.out.println("1 根节点:");// A
        root.printLevelOrder();
        System.out.println("1 中序子树"+inorderTraversal);//DBE CF
        System.out.println("1 后序子树"+postorderTraversal);//DEB FC

        ///*
            for (int i = 0; i < postorderTraversal.size(); i++) {
                System.out.println("-------循环开始-------");
                //后序遍历的最后一个是根节点,遍历中序找到后序的最后一个节点值的位置
                System.out.println("中序i="+i+",值为"+inorderTraversal.get(i));
                System.out.println("后序i="+i+",值为"+postorderTraversal.get(i));
                System.out.println("根节点值为:"+postorderTraversal.get(n - 1));
                if (inorderTraversal.get(i).equals(postorderTraversal.get(n - 1))) {
                    //将根节点加入根节点链表
                    //rootNode.add(postorderTraversal.get(n - 1));
                    System.out.println("找到了根节点:"+inorderTraversal.get(i));
                    rootNode.add(root);
                    System.out.println("当前根节点链表为"+rootNode);
                    break;
                } else {
                    System.out.println("未找到根节点将"+inorderTraversal.get(i)+"加入中序左子树leftSubTreeIT");
                    System.out.println("未找到根节点将"+postorderTraversal.get(i)+"加入后序左子树leftSubTreePT");
                    //没找到时,后序遍历左子树添加后序遍历的数值
                    leftSubTreePT.add(postorderTraversal.get(i));
                    //中序遍历添加中序遍历的数值
                    leftSubTreeIT.add(inorderTraversal.get(i));
                    System.out.println("2 中序左子树"+leftSubTreeIT);
                    System.out.println("2 后序左子树"+leftSubTreePT);
                }
            }
            //从链表的最后开始转存入
            for (int i = leftSubTreePT.size(); i<n-1; i++) {
                rightSubTreePT.add(postorderTraversal.get(i));
                rightSubTreeIT.add(inorderTraversal.get(i + 1));
                System.out.println("2 中序右子树"+rightSubTreeIT);
                System.out.println("2 后序右子树"+rightSubTreePT);
            }
        System.out.println("-------分割后检查-------");
            System.out.println("3 根节点:");// A
            root.printLevelOrder();
            System.out.println("3 中序左子树"+leftSubTreeIT);//DBE
            System.out.println("3 后序左子树"+leftSubTreePT);//DEB
            System.out.println("3 中序右子树"+rightSubTreeIT);//CF
            System.out.println("3 后序右子树"+rightSubTreePT);//FC
        //左节点加入方法
        //左子树的长度不为零,将左子树的后序遍历的末尾作为当前root的左节点
        if (leftSubTreePT.size()>0) {
            int leftSize = leftSubTreePT.size();
            TreeNode LeftNode = new TreeNode(leftSubTreePT.get(leftSize-1));
            root.left = LeftNode;
        }
        //右节点加入方法
        //右子树的长度不为零,将右子树的后序遍历的末尾作为当前root的左节点
        if (rightSubTreePT.size()>0) {
            int rightSize = rightSubTreePT.size();
            TreeNode RightNode = new TreeNode(rightSubTreePT.get(rightSize-1));
            root.right = RightNode;
        }
            //递归
        System.out.println("----------递归开始---------");
        if (leftSubTreePT.size()>1) {
            splitLRSubTree(leftSubTreePT,leftSubTreeIT,root.left);//DEB DBE
        }
        if (rightSubTreePT.size()>1) {
            splitLRSubTree(rightSubTreePT,rightSubTreeIT,root.right);//FC CF
        }
        System.out.print("当前二叉树的层次遍历为:");
        root.printLevelOrder();
        System.out.println("根节点链表长度为:"+root.countNodes());
        //若树节点数等于所有节点数,返回
        if (root.countNodes()==n) {
            return root;
        }
       // */
        return root;
    }

    static class TreeNode{
        String value;
        TreeNode left;
        TreeNode right;

        TreeNode(String value){
            this.value = value;
            this.left = null;
            this.right = null;
        }
        public int countNodes() {
            if (this == null) {
                return 0;
            }
            return 1 + (left != null ? left.countNodes() : 0) + (right != null ? right.countNodes() : 0);
        }

        public void printLevelOrder() {
            if (this == null) {
                return;
            }
            Queue<TreeNode> queue = new LinkedList<>();
            queue.add(this);
            StringBuilder result = new StringBuilder();
            while (!queue.isEmpty()) {
                TreeNode node = queue.poll();
                result.append(node.value).append(" "); // 将节点值添加到结果中,并用空格分隔
                if (node.left != null) {
                    queue.add(node.left);
                }
                if (node.right != null) {
                    queue.add(node.right);
                }
            }
            System.out.println(result.toString().trim()); // 打印整个结果,并去除末尾的多余空格
        }

        public String toString(){
            return value;
        }
    }
}

  • 16
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值