二叉树的创建——递归与非递归

目录

一、知识铺垫

二、二叉树的创建之递归

三、二叉树的创建之非递归(迭代)


          初学者对于二叉树的遍历(前序遍历,中序遍历,后序遍历,层序遍历),这些放在最早学习的内容,应该是非常熟悉的,但是渐渐的就会发现,对于如何创建一颗二叉树,初学者对此过程还不甚清晰。直接一个一个结点插入吗?当树的深度过大时,这显然是一个费时费力的过程。以下我们介绍二叉树的创建的两种方法——递归与非递归。

一、知识铺垫

           创建任意一颗树,在不知道null值归属于哪个结点时,仅仅依靠 单独的遍历字符串 是没有办法把一棵树创建好的。

            例如:当我们不知道null值归属与哪个结点时,则说明我们可以往遍历中的任意位置插入结点。

            层序遍历:3,9,null,null,20,15,7

            层序遍历:3,9,null,20,null,15,7

        所以我们直到了单独的一种不知道null结点的遍历时无法准确创建出一棵树的,从遍历的特性我们可以知道,前序和后序可以确认根结点,中序可以确认左右子树,当我们要创建树时(遍历字符串中无null值),至少应该满足以下特性:

  1. 至少应提供两个以上的遍历字符串
  2. 一定要提供中序字符串

        当然,当遍历字符串中带了null值时,任意一种遍历字符串均能准确建树,我们这里讨论不带null值的情况。

二、二叉树的创建之递归

        例:当前序遍历以及中序遍历已经被提供时。

        前序:A B K M N O P L C D E  H I J F G(下述图片前序有误,以此为准)

        中序:M N P O K L B A E D H I J F G C

最终树的图像: 

  

代码:

public TreeNode root;
    public BinaryTree(String preOrder,String inOrder){
        root=createBinaryTreeByRecursive(preOrder,inOrder);
    }
    private TreeNode createBinaryTreeByRecursive(String preOrder,String inOrder){
        return create(preOrder,inOrder,0,inOrder.length()-1);
    }
    private int index=0;//千万注意preOder的下标要放在递归函数外边,因为其不能回退
    private BinaryTree.TreeNode create(String preOrder, String inOrder, int left, int right){
        if(left>right){
            return null;
        }
        //为每一个字符创建新的结点
        BinaryTree.TreeNode node=new BinaryTree.TreeNode(preOrder.charAt(index));
//可加可不加
//        if(left==right){
//            index++;
//            return node;
//        }
        int rootIndex=left-1;//记录根的下标
        //找到根结点在中序中的位置,以便确定左右子树
        for(int i=left;i<=right;i++){
            if(preOrder.charAt(index)==inOrder.charAt(i)){
                rootIndex=i;
                break;
            }
        }
        //在序列中找到了根节点的位置
        if(rootIndex>=left) {
            index++;
        }
        node.leftChild=create(preOrder,inOrder,left,rootIndex-1);
        node.rightChild=create(preOrder,inOrder,rootIndex+1,right);
        return node;
    }

同理,给定后序和中序即将从后往前遍历后序代码

也可以增加HashMap来减少搜索根节点的过程

三、二叉树的创建之非递归(迭代)

       在明白和熟悉了递归创建二叉树后,我们可以开始着手非递归创建二叉树了。而最主要的就是把左子树与右子树的范围确认好,所以我们可以利用栈,来判定其接下来是建左子树还是右子树。

代码:

private TreeNode createBinaryTreeByStack(String preOrder,String inOrder){
        Stack<TreeNode> stack=new Stack<>();
        int inIndex=0;
        TreeNode root=new TreeNode(preOrder.charAt(0));
        stack.push(root);
        TreeNode cur=root;
        for(int i=1;i<preOrder.length();i++){
            if(stack.peek().val==inOrder.charAt(inIndex)){
                //判断哪些结点左子树已经建完
                while(!stack.empty()&&stack.peek().val==inOrder.charAt(inIndex)){
                    cur= stack.pop();
                    inIndex++;
                }
                cur.rightChild=new TreeNode(preOrder.charAt(i));
                stack.push(cur.rightChild);
            }else{
                //左子树没有走完,继续建左子树
                cur=stack.peek();
                cur.leftChild=new TreeNode(preOrder.charAt(i));
                stack.push(cur.leftChild);
            }
        }
        return root;
    }

       时刻记住前序是根-左子树-右子树,而中序是左子树-根-右子树,所以栈中用来存储还未走右子树的根,当栈顶元素与中序中元素一致时,说明此节点的左子树已经走完了(建完了),要开始建右子树了,所以将其从栈中pop()出来,建立其右子树。

      每一个结点都可以是根可以把前序和中序理解成是无数个根按照一定的顺序排列在一起,所以当前序的根与中序的根一致时,可以表明,这个结点,已经把中序的左子树-根当中的左子树建完了。

      同理可得,当是后序左子树-右子树-根和中序左子树-根-右子树的时候,我们应该从后遍历后序字符串,同时从后遍历中序字符串,当后序字符串中的元素与中序字符串中的元素一致的时候,我们可以认为,这个结点,已经建完了其右子树,要开始建其左子树了,从而将此结点从栈中pop出。

可以做题练手:

LeetCode-105

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值