栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

二叉树练习题

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

二叉树练习题

文章目录
  • 1. 获取树中节点的个数
  • 2. 获取叶子节点的个数 - (遍历思路、子问题思路)
  • 3. 获取第K层节点的个数
  • 4. 获取二叉树的高度
  • 5. 检测值为value的元素是否存在
  • 6. 判断一棵树是不是完全二叉树
  • 7. 相同的树
  • 8. 另一棵树的子树
  • 9. 二叉树的最大深度 - 和上面二叉树高度相同
  • 10. 平衡二叉树
  • 11. 对称二叉树
  • 12. 二叉树遍历
  • 13. 层序遍历
  • 14. 二叉树的最近公共祖先
  • 15. 二叉搜索树与双向链表
  • 16. 从前序与中序遍历序列构造二叉树
  • 17. 从中序与后序遍历序列构造二叉树
  • 18. 根据二叉树创建字符串
  • 19. 前序遍历 - 非递归
  • 20. 中序遍历 - 非递归
  • 21. 后序遍历 - 非递归

1. 获取树中节点的个数
int count = 0;
int size(TreeNode root){
    if (root == null){
        return 0;
    }
    count++;
    return size(root.left)+size(root.right);
}

int size1(TreeNode root){
    if (root == null) return 0;
    //左子树和右子树之和+根节点
    return size1(root.left)+size1(root.right)+1;
}
2. 获取叶子节点的个数 - (遍历思路、子问题思路)
  • 遍历思路:遍历到叶子结点,就让计数器++
int leafCount = 0;
void getLeafNodeCount(TreeNode root){
    if(root == null){
        return;
    }
    //左子树和右子树都为null时,是叶子结点
    if (root.left == null && root.right ==null){
        leafCount++;
    }
    //递归左子树和右子树
    getLeafNodeCount(root.left);
    getLeafNodeCount(root.right);
  • 子问题思路 :左树叶子数 +右树叶子数 = 整棵树的叶子
int leafCount1 = 0;
int getLeafNodeCount1(TreeNode root) {
    if (root == null) {
        return 0;
    }
    if (root.left == null &&root.right == null){
        //当前的root没有子树,自己就是叶子节点
        return 1;
    }
    return getLeafNodeCount1(root.left) + getLeafNodeCount1(root.right);
}
3. 获取第K层节点的个数
  • 子问题思路:是根节点的第k层,也就是第二层结点的第k-1层
public int getKLevelNodeCount(TreeNode root,int k){
    if (root == null || k <= 0){
        return 0;
    }
    if (k == 1){ //当k=1时,第一层
        return 1;
    }
    //k不为1时:递归
    return getKLevelNodeCount(root.left,k-1) + getKLevelNodeCount(root.right,k-1);
}
4. 获取二叉树的高度
  • 子问题思路:左树的高度和右树的高度 取最大值 然后+1(根节点)= 整棵树的高度
  • 下面的函数时间复杂度:O(n) (看递归的次数,每个结点都递归,次数为n)
  • 空间复杂度:O(k) k=log2(n) (空间复杂度为数的高度)
int getHeight2(TreeNode root) {
    if(root == null){
        return 0;
    }
    int leftHeight = getHeight2(root.left);
    int rightHeight = getHeight2(root.right);
    return leftHeight>=rightHeight ? leftHeight+1 : rightHeight+1;


}
int getHeight(TreeNode root){
    if(root == null){
        return 0;
    }
    //比较左树高度和右树高度,取最大值
    int leftHeight = getHeight(root.left);
    int rightHeight = getHeight(root.right);
    return leftHeight > rightHeight ? leftHeight+1 : rightHeight+1;

   //return getHeight(root.left) > getHeight(root.right)? (getHeight(root.left)+1):(getHeight(root.right)+1);
   //递归的次数太多了,重复计算了好多次,err
        //超出规定的运行时间:1.死循环 2.递归的次数太多了
}
5. 检测值为value的元素是否存在
TreeNode find(TreeNode root,char val) {
    if (root == null) return null;
    if (root.val == val){
        return root;
    }
    TreeNode ret = find(root.left,val);
    if(ret!=null){
        return ret;
    }
    ret = find(root.right,val); //如果左子树没有值为value的元素,看看右子树
    if (ret != null){
        return ret;
    }
    return null;
}
6. 判断一棵树是不是完全二叉树
  • 思路:root为空返回true,不为空时,建立一个队列,将root放入队列,
  • 队列不为空时,每次取出队列队头元素,对头元素不为null,则加入对头元素的左子树和右子树,为null则中止循环
  • 之后,队列不为空时,检测队列中所有元素,如果都是null则为true,如果有别的元素,则为false
{
    if(root == null){
        return true;
    }
    //队列
    Queue queue = new LinkedList<>();
    queue.offer(root);//将根入队列
    //循环
    while (!queue.isEmpty()){// 队列不为空
        TreeNode cur = queue.poll(); //取出队头元素给cur
        if (cur != null){  //当取出的队头不为null时,加入其左子树和右子树两个元素
            queue.offer(cur.left);
            queue.offer(cur.right);
        }else {
            break; //为null时,中止循环
        }
    }
    //看队列剩下的元素是否都为null,如果有不为null的元素,那么就不是完全二叉树
    while(!queue.isEmpty()){
        TreeNode top = queue.peek();
        if(top != null){
            return false;
        }
        queue.poll();
    }
    return true;
}
7. 相同的树

时间复杂度:O(min(M,N))

  • https://leetcode.cn/problems/same-tree/
public boolean isSameTree(TreeNode p, TreeNode q) {
    if(p == null && q == null){ //p和q都为空
        return true;
    }
    if(p == null && q!=null || p!=null && q == null){ //p为空或者q为空
        return false;
    }
    if(p.val != q.val){ //p和q的数值不同
        return false;
    }
    return isSameTree(p.left,q.left) && isSameTree(p.right,q.right);
}
8. 另一棵树的子树
  • https://leetcode.cn/problems/subtree-of-another-tree/
  • 思路:
  • 1.先判断 两棵树 是不是两棵相同的树
  •  2.如果不是,分别判断,subRoot是不是root的左子树或者右子树
    
  • 时间复杂度:O(m * n)
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
        //一个为空,有个不为空
        if(root == null || subRoot == null){
            return false;
        }
//        if(root == null && subRoot == null) {
//            return true;
//        }
//        if(root != null && subRoot == null && root == null && subRoot != null) {
//            return false;
//        } 这两个条件和上面的条件相同
        //根节点和subroot是不是两颗相同的树
        if(isSameTree(root,subRoot)){
            return true;
        }
        //判断subRoot是不是root的左子树或者右子树
        if(isSubtree(root.left,subRoot)){
            return true;
        }
        if(isSubtree(root.right,subRoot)){
            return true;
        }
        return false;

    }
9. 二叉树的最大深度 - 和上面二叉树高度相同
  • https://leetcode.cn/problems/maximum-depth-of-binary-tree/
  • 时间复杂度:O(n);
public int maxDepth(TreeNode root) {
    if(root == null){
        return 0;
    }
    int leftHeight = maxDepth(root.left);
    int rightHeight = maxDepth(root.right);
    return leftHeight > rightHeight ? leftHeight+1:rightHeight+1;

}
10. 平衡二叉树
  • https://leetcode.cn/problems/balanced-binary-tree/
//时间复杂度:O(n);
public int Height(TreeNode root){
    if(root == null){
        return 0;
    }
    int leftHeight = Height(root.left);
    int rightHeight = Height(root.right);
    return leftHeight > rightHeight? leftHeight+1 :rightHeight+1;
}
// 时间复杂度:O(N^2)
//一棵树 要是平衡二叉树,那么每棵子树都是平衡二叉树
public boolean isBalanced(TreeNode root) {
     if(root == null){
        return true;
     }
     int left = Height(root.left);
     int right = Height(root.right);
//左树高度和右树高度差小于1,同时满足root的左树是平衡的,右树也是平衡的
     return (Math.abs(left - right)<=1) && isBalanced(root.left) && isBalanced(root.right);
    }

//为了减少时间复杂度,一边检测高度,一边反馈是否平衡

public int Height2(TreeNode root){
     if(root == null){
        return 0;
     }
     int leftHeight = Height(root.left);
     int rightHeight = Height(root.right);
     //如果左右子树的差值大于1,则不平衡,返回
     //因为返回-1之后,另一各子树可能会为0,差值就变成了等于1,返回1,所以需要制止这种,在条件中加入左子树和右子树必须>=0
     if(leftHeight >=0 && rightHeight>=0 && Math.abs(leftHeight-rightHeight)<=1){
           return Math.max(leftHeight,rightHeight) + 1;
     }else{
          //说明不平衡
           return -1;
     }
}
public boolean isBalanced2(TreeNode root) {
     if(root == null){return true;}
        return Height(root)>=0;
     }
11. 对称二叉树

https://leetcode.cn/problems/symmetric-tree/

public boolean isSymmetricChild(TreeNode leftTree,TreeNode rightTree) {
    //根的左子树和右子树都为空,则为真
    if(leftTree == null &&rightTree == null){
        return true;
    }
    //根的左子树和右子树一个为空,一个不为空,则为假
    if(leftTree == null && rightTree!=null || leftTree!=null && rightTree == null){
        return false;
    }
    //根的左子树和右子树的数值不同,为假
    if(leftTree.val != rightTree.val){
        return false;
    }
    //左子树的左子树和右子树的右子树相同,则为真
    return isSymmetricChild(leftTree.left,rightTree.right) && isSymmetricChild(leftTree.right,rightTree.left);
}

public boolean isSymmetric(TreeNode root) {
        if(root == null){
            return true;
        }
        return isSymmetricChild(root.left,root.right);
}
12. 二叉树遍历

https://www.nowcoder.com/practice/4b91205483694f449f94c179883c1fef?tpId=60&&tqId=29483&rp=1&ru=/activity/oj&qru=/ta/tsing-kaoyan/question-ranking

class TreeNode{
    public char val;
    public TreeNode left;
    public TreeNode right;
    public  TreeNode(char val){
        this.val = val;
    }
}
class solution{
    public static int i = 0; //i遍历字符串
    public static TreeNode createTree(String str){
        TreeNode root = null;
        if(str.charAt(i)!='#'){
            root = new TreeNode(str.charAt(i));//建立根的结点
            i++;
            // 左子树和右子树
            root.left = createTree(str);
            root.right = createTree(str);
        }else{
            i++; //当为#时,表示为空树,i++
        }
        return root;
    }
    //对二叉树中序排列 左中右
    public static void inorder(TreeNode root){
        if(root == null){
            return;
        }
        inorder(root.left);
        System.out.print(root.val+" ");
        inorder(root.right);
    }
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别,
        // hasNext遇到空格结束,hasNextLine遇到空格不结束
        while (in.hasNextLine()) { // 注意 while 处理多个 case
            String str = in.nextLine();
            TreeNode root = createTree(str);
            inorder(root);
        }
    }
13. 层序遍历

https://leetcode.cn/problems/binary-tree-level-order-traversal/

public void levelOrder(TreeNode root) {
    //队列表示
    Queue queue= new LinkedList<>();
    if (root == null){
        return;
    }
    queue.offer(root);
    if(!queue.isEmpty()){
        TreeNode cur = queue.poll();
        System.out.print(cur.val+" ");
        if(cur.left!=null){
            queue.offer(cur.left);
        }
        if(cur.right!=null){
            queue.offer(cur.right);
        }
    }
}

//新建一个队列,在队列中,最先加入根节点,之后移除,再加入根节点的左右节点(前提是,如果为null就不加入队列中)
//list - 每层节点数,都是看队列中的节点数量
public List> levelOrder1(TreeNode root) {
        List> ret = new ArrayList<>();
        if(root == null){
            return ret; //root == null时,希望得到的数值是空的,但是地址不为空
        }
        Queue queue = new LinkedList<>();
        queue.offer(root);

        while(!queue.isEmpty()){
            int size = queue.size(); //这个值代表 当前层有多少个结点
            List list = new ArrayList<>(); //新建list装一层的结点
            while(size != 0){
                TreeNode cur = queue.poll();
               // list.add(cur.val);
                if(cur.left!=null){ //与遍历节点问题不同的是:如果是null就不添加到que中
                    queue.offer(cur.left);
                }
                if(cur.right!=null){
                    queue.offer(cur.right);
                }
                size--;
            }
            ret.add(list);
        }
        return ret;
    }
14. 二叉树的最近公共祖先

https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/

//方法1:二叉搜索树的思想 (左子树数值<根数值<右子树数值)
 // 分三种情况,1.p和q有一个是root,那么公共祖先就是root;2.p和q在root的两侧,公共祖先是root;
 // 3.p和q都在root的左树或者右树,公共祖先在root的左树或者右树当中

 public TreeNode lowestCommonAncestor1(TreeNode root, TreeNode p, TreeNode q) {
     if(root == null) {
         return null;
     }

     if(root == p || root == q) {
         return root;
     }

     TreeNode leftT = lowestCommonAncestor(root.left,p,q);
     TreeNode rightT = lowestCommonAncestor(root.right,p,q);

     if(leftT != null && rightT != null) {
         return root;
     }else if(leftT != null) {
         return leftT;
     }else {
         return rightT;
     }
 }

 //方法2:思路:假设这可二叉树 是使用孩子双亲表示法 表示的
    //可以把问题转换为 链表求交点 但是二叉树 每个结点 是没有双亲结点的
    //1.用两个栈存储路径,
    //2.求栈的大小
    //3.让栈中多的元素 取出差值个 元素
    //4.之后再同时出栈,如果栈顶元素相同,则为公共祖先


    //难点:如何去找到从根节点到一个指定节点的路径?

    //用两个栈表示p和q的路径
    //找到p,q的地址
    //root:根节点 node:指定的节点 stack:存放从根节点到指定节点的路径
public Boolean getPath(TreeNode root,TreeNode node,Stack stack){
        if(root == null || node == null){
            return false;
        }
        //root不为null,将root入栈
        stack.push(root);

        if(root == node){
            return true;
        }
        //如果root!=node,先将root放入栈中
        //将左子树带入递归
        Boolean flg = getPath(root.left,node,stack);
        if(flg){
            return true; //如果在左子树中找到了,返回true
        }
        //左子树中没找到,在右子树中找
        flg = getPath(root.right,node,stack);
        if(flg){
            return true;
        }
        //如果不是true,则从栈中去除
        stack.pop();
        return false;
    }
  public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null){
            return null;
        }
        //建立两个栈,一个p,一个q
        Stack stack1 = new Stack<>();
        Stack stack2 = new Stack<>();
        getPath(root,p,stack1);
        getPath(root,q,stack2);
        //看p和q的栈中元素多少,多的栈就将元素去除size个
        int size1 = stack1.size();
        int size2 = stack2.size();
        if(size1 > size2){
            int size = size1 - size2;
            while(size!=0){
                stack1.pop();
                size--;
            }
            while(!stack1.isEmpty() && !stack2.isEmpty()){
                if(stack1.peek() == stack2.peek()){
                    return stack1.pop();
                }else{
                    stack1.pop();
                    stack2.pop();
                }
            }
        }else{
            int size = size2 - size1;
            while(size!=0){
                stack2.pop();
                size--;
            }
            while(!stack1.isEmpty() && !stack2.isEmpty()){
                if(stack1.peek() == stack2.peek()){
                    return stack1.pop();
                }else{
                    stack1.pop();
                    stack2.pop();
                }
            }
        }
        return null;
    }
15. 二叉搜索树与双向链表

https://www.nowcoder.com/practice/947f6eb80d944a84850b0538bf0ec3a5?tpId=13&&tqId=11179&rp=1&ru=/activity/oj&qru=/ta/coding-interviews/question-ranking

// 排序:可以中序遍历这棵二叉搜索树 left变成双向链表的前驱,right变成双向链表的后继
// 需要在遍历过程中修改每个结点的left和right
//修改指向是重点
//相当于对二叉搜索树进行排序

TreeNode prev = null;
public void inorder1(TreeNode pCur) {
        if (pCur == null) {
            return;
        }
        //左子树
        inorder(pCur.left);
        pCur.left = prev; //将pCur的左修改为prev
        if (prev != null) {
            prev.right = pCur;//prev的右就为pCur
        }
        prev = pCur; //prev修改到pCur
        //右子树
        inorder(pCur.right);

    }
    public TreeNode Convert(TreeNode pRootOfTree) {
        if (pRootOfTree == null) {
            return null;
        }
        inorder(pRootOfTree);
        // 创建头结点
        TreeNode head = pRootOfTree;
        while (head.left != null) {
            head = head.left;
        }
        return head;

    }
16. 从前序与中序遍历序列构造二叉树
  • https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/
  public int preIndex = 0;
  //用先序遍历和中序遍历创建二叉树
  public TreeNode createTreeByPandI(int[] preorder,int[] inorder,int inbegin,int inend){
        //递归中止条件
        if(inbegin > inend){
            //如果满足这个条件说明没有左树也没有右树,是终节点
            return null;
        }
        //建立根节点
        TreeNode root = new TreeNode(preorder[preIndex]);
        //寻找根节点在中序遍历数组中的位置
        int rootIndex = findIndexOdI(inorder,inbegin,inend,preorder[preIndex]);
        preIndex++;
        //分别建立左子树 和 右子树,顺序不能颠倒
        root.left = createTreeByPandI(preorder,inorder,inbegin,rootIndex-1);
        root.right = createTreeByPandI(preorder,inorder,rootIndex+1,inend);
        return root;
    }

    //在中序遍历中寻找前序遍历下标为pi的数在哪里
    private int findIndexOdI(int[] inorder,int inbegin,int inend,int key){
        for(int i = inbegin;i<=inend ; i++){
            if(inorder[i] == key){
                return i;
            }
        }
        return -1;
    }

    //将先序遍历pi下标的元素创建为root
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        if(preorder == null || inorder == null){
            return null;
        }
        return createTreeByPandI(preorder,inorder,0,inorder.length-1);
    }
17. 从中序与后序遍历序列构造二叉树

https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal/

public int postIndex = 0;
 public TreeNode createByPandI(int[] inorder,int[] postorder,int inbegin,int inend){
        //中止条件
        if(inbegin>inend){
            return null;
        }

        TreeNode root = new TreeNode(postorder[postIndex]);
        //根节点在中序遍历的位置
        int rootIndex = findIndexOd(inorder,inbegin,inend,postorder[postIndex]);
        postIndex--;

        //因为后序遍历中根结点在最后,它的前一位在中序遍历的根节点的右子树
        //所以建立右子树,在加你左子树
        root.right = createByPandI(inorder,postorder,rootIndex+1,inend);
        root.left = createByPandI(inorder,postorder,inbegin,rootIndex-1);

        return root;

    }
    public int findIndexOd(int[] inorder,int inbegin,int inend,int key){
        for(int i = inbegin; i<= inend ; i++){
            if(inorder[i] == key){
                return i;
            }
        }
        return -1;
    }
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        //如果为空,返回null
        if(inorder == null || postorder == null){
            return null;
        }
        postIndex = postorder.length-1;
        return createByPandI(inorder,postorder,0,inorder.length-1);
    }
18. 根据二叉树创建字符串

https://leetcode.cn/problems/construct-string-from-binary-tree/

public void treeToString(TreeNode root,StringBuilder sb){
    if(root == null){
        return;
    }
    sb.append(root.val); //因为是前序遍历,现将根节点数值放入字符串
    if(root.left != null){
        sb.append("(");
        treeToString(root.left,sb);
        sb.append(")");//返回时)
    }else{
        //左右子树都为空
        if(root.right == null){
            return;
        }else{
            //左为空,右不为空时
            sb.append("(");
            sb.append(")");
        }
    }
    if(root.right != null){
        sb.append("(");
        treeToString(root.right,sb);
        sb.append(")");
    }

}
public String tree2str(TreeNode root) {
    if(root == null){
        return null;
    }
    StringBuilder sb = new StringBuilder();
    treeToString(root,sb);
    return sb.toString();
}
19. 前序遍历 - 非递归
public void preOrder1(TreeNode root) {
        Stack stack = new Stack<>();
        TreeNode cur = root;
        while(cur!= null || !stack.empty()) {
            while (cur != null) {
                stack.push(cur);
                System.out.println(cur.val + " ");
                cur = cur.left;
            }
            TreeNode top = stack.pop(); //记录根节点
            cur = top.right;

        }

    }
20. 中序遍历 - 非递归
public void inOrder1(TreeNode root) {
    //新建一个栈
    Stack stack = new Stack<>();
    TreeNode cur = root;
    while(cur!=null || !stack.empty()){
        while(cur != null){
            stack.push(cur);
            cur = cur.left;
        }
        TreeNode top = stack.pop();
        System.out.println(top.val+" ");
        cur = top.right;
    }
}
21. 后序遍历 - 非递归
//左子树和右子树都为空的时候才能打印根节点
    public void postOrder1(TreeNode root) {
        Stack stack = new Stack<>();
        TreeNode cur = root;
        TreeNode prev = null;
        while (cur!=null || !stack.empty()){
            while (cur!=null){
                stack.push(cur);
                cur = cur.left;
            }
            TreeNode top = stack.peek();
            //为了防止死循环 在条件中加一个打印过的不能再打印
            // 如果当前节点的右子树被打印过 或者 遍历过  直接弹出了
            if(top.right == null || prev == top.right){
                stack.pop();
                System.out.println(top.val+" ");
                prev = top;///记录一下 最近一次打印的结点

            }else{
                cur = top.right;
            }
        }
    }

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/996541.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号