二叉树

零.节点类

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */

一,二叉树的遍历

1.二叉树的前序遍历(根左右)

class Solution {
    public List<Integer> list = new ArrayList<>();

    public List<Integer> preorderTraversal(TreeNode root) {
        bianLi(root);
        return list;
    }

    public void bianLi(TreeNode root) {
        if (root == null) {
            return;
        }
        list.add(root.val);
        bianLi(root.left);
        bianLi(root.right);
    }
}

2.二叉树的中序遍历(左根右)

class Solution {
    public List<Integer> list = new ArrayList<>();

    public List<Integer> inorderTraversal(TreeNode root) {
        bianLi(root);
        return list;
    }

    public void bianLi(TreeNode root) {
        if (root == null) {
            return;
        }
        bianLi(root.left);
        list.add(root.val);
        bianLi(root.right);
    }
}

3.二叉树的后序遍历(左右根)

class Solution {
    public List<Integer> list = new ArrayList<>();

    public List<Integer> postorderTraversal(TreeNode root) {
        bianLi(root);
        return list;
    }

    public void bianLi(TreeNode root) {
        if (root == null) {
            return;
        }
        bianLi(root.left);
        bianLi(root.right);
        list.add(root.val);
    }
}

4.二叉树的层序遍历

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

class Solution {
    public Queue<TreeNode> queue = new LinkedList<>();

    public List<List<Integer>> levelOrder(TreeNode root) {
        // 如果根结点为空,返回空集合
        if (root == null) {
            return new ArrayList<>();
        }
        List<List<Integer>> lists = new ArrayList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            // 存放每次的结点值
            List<Integer> list = new ArrayList<>();
            // 每层的结点数
            int levelNum = queue.size();
            // 从左向右依次遍历每层的节点
            for (int i = 0; i < levelNum; i++) {
                // 将该层的节点值放进list集合
                TreeNode node = queue.poll();
                list.add(node.val);
                // 将该节点不为空的左右节点按顺序添加进队列
                if (node.left != null) {
                    queue.offer(node.left);
                }
                if (node.right != null) {
                    queue.offer(node.right);
                }
            }
            lists.add(list);

        }
        return lists;
    }
}

class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;

    TreeNode() {
    }

    TreeNode(int val) {
        this.val = val;
    }

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

二,根据二叉树的遍历还原二叉树 

1.根据二叉树的中序遍历和后序遍历还原二叉树

题目描述

给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。

代码实现

import java.util.HashMap;
import java.util.Map;

class Solution {
    public Map<Integer, Integer>map=new HashMap<>();
    // inorder:中序遍历结果,postorder后序遍历结果
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        for(int i=0;i<inorder.length;i++) {
            map.put(inorder[i], i);
        }
        return DTBuildTree(inorder, postorder, 0, inorder.length - 1,0,inorder.length - 1);
    }

    private TreeNode DTBuildTree(int[] inorder, int[] postorder, int head1, int end1,int head2,int end2) {
        if (head1 == end1) {
            return new TreeNode(inorder[head1]);
        }
        if (head1 > end1) {
            return null;
        }
        // 获取根结点的值
        int val = postorder[end2];
        // 创建根结点
        TreeNode rootNode = new TreeNode(val);
        // 找到根结点在中序遍历中出现的下标
        int mid =map.get(val);

        int leftSize=mid-head1;
        // 以根结点来划分中序遍历中左右子树,mid左边是左子树,右边是右子树
        rootNode.left = DTBuildTree(inorder, postorder, head1, mid - 1,head2,head2+leftSize-1);
        rootNode.right = DTBuildTree(inorder, postorder, mid + 1, end1,head2+leftSize,end2-1);
        return rootNode;
    }

}

链接:https://leetcode-cn.com/leetbook/read/data-structure-binary-tree/xo98qt/

 

2.根据二叉树的前序遍历和中序遍历还原二叉树

题目描述

给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。

代码实现

import java.util.HashMap;
import java.util.Map;

import java.util.HashMap;
import java.util.Map;

class Solution {
    int[] preorder;
    int[] inorder;
    public Map<Integer, Integer> map = new HashMap<>();


    public TreeNode buildTree(int[] preorder, int[] inorder) {
        this.preorder = preorder;
        this.inorder = inorder;
        for (int i = 0; i < inorder.length; i++) {
            map.put(inorder[i], i);
        }
        return DTbuildTree(0, preorder.length - 1, 0, inorder.length - 1);
    }
     //head1和end1为先序遍历起点和终点,head2和end2为中序遍历起点和终点
    public TreeNode DTbuildTree(int head1, int end1, int head2, int end2) {
        if (head2 > end2) {
            return null;
        }
        if (head2 == end2) {
            return new TreeNode(inorder[head2]);
        }
        int val = preorder[head1];
        int mid = map.get(val);
        TreeNode rooTreeNode = new TreeNode(val);
        //leftSize为左节点个数,中序遍历中根节点减去中序遍历的起点
        int leftSize = mid-head2;
        rooTreeNode.left = DTbuildTree(head1 + 1, leftSize, head2, mid - 1);
        //右边先序遍历的起点为起点加1再加上左节点个数,中序遍历为右边子树的起点为根节点下标加一
        rooTreeNode.right = DTbuildTree(head1+leftSize + 1, end1, mid + 1, end2);
        return rooTreeNode;
    };
}

链接:https://leetcode-cn.com/leetbook/read/data-structure-binary-tree/xoei3r/

 

3.根据二叉树先序遍历还原二叉树

题目描述

我们从二叉树的根节点 root 开始进行深度优先搜索。

在遍历中的每个节点处,我们输出 D 条短划线(其中 D 是该节点的深度),然后输出该节点的值。(如果节点的深度为 D,则其直接子节点的深度为 D + 1。根节点的深度为 0)。

如果节点只有一个子节点,那么保证该子节点为左子节点。

给出遍历输出 S,还原树并返回其根节点 root。

代码实现

class Solution {
    public int index = 0;

    public TreeNode recoverFromPreorder(String traversal) {
        if (traversal == null) {
            return null;
        }
        return genTree(0, traversal);
    }

    private TreeNode genTree(int depth, String traversal) {
        // TODO Auto-generated method stub
        // 1.获取该节点深度
        int curDepth = 0;
        while (index < traversal.length() && traversal.charAt(index) == '-') {
            curDepth++;
            index++;
        }
        // 2.比较该节点深度和目标深度是否相等,如果不相等,则说明该位置节点为null,该节点是上一层的子节点,index退回到刚进入该方法的值
        if (curDepth != depth) {
            index -= curDepth;
            return null;
        }
        // 3.获取该节点的值
        int val = 0;
        while (index < traversal.length() && Character.isDigit(traversal.charAt(index))) {
            int t = traversal.charAt(index) - '0';
            val = val * 10 + t;
            index++;
        }
        // 4.创建节点(将值放入构造器),深度加一,将创建节点的左右节点赋值,返回创建节点
        TreeNode treeNode = new TreeNode(val);
        // 如果节点只有一个子节点,那么保证该子节点为左子节点
        treeNode.left = genTree(depth + 1, traversal);
        treeNode.right = genTree(curDepth + 1, traversal);
        return treeNode;
    }
}

链接:https://leetcode-cn.com/problems/recover-a-tree-from-preorder-traversal

三,完全二叉树

1.如何判断完全二叉树

判断一棵树是否是完全二叉树的思路 [3] 

1>如果树为空,则直接返回错

2>如果树不为空:层序[遍历](https://baike.baidu.com/item/遍历/9796023)二叉树

2.1>如果一个结点左右孩子都不为空,则pop该节点,将其左右孩子入队列;

2.1>如果遇到一个结点,左孩子为空,右孩子不为空,则该树一定不是完全二叉树;

2.2>如果遇到一个结点,左孩子不为空,右孩子为空;或者左右孩子都为空,且则该节点之后的队列中的结点都为叶子节点,该树才是完全二叉树,否则就不是完全二叉树; [3] 

 

2.根据完全二叉树的后序遍历求层序遍历

题目描述:

一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是完美二叉树。对于深度为 D 的,有 N 个结点的二叉树,若其结点对应于相同深度完美二叉树的层序遍历的前 N 个结点,这样的树就是完全二叉树

给定一棵完全二叉树的后序遍历,请你给出这棵树的层序遍历结果。

输入格式

输入在第一行中给出正整数 N(≤30),即树中结点个数。第二行给出后序遍历序列,为 N 个不超过 100 的正整数。同一行中所有数字都以空格分隔。

输出格式

在一行中输出该树的层序遍历序列。所有数字都以 1 个空格分隔,行首尾不得有多余空格。

输入样例

8
91 71 2 34 10 15 55 18

输出样例

18 34 55 71 2 10 15 91

思路分析

由于其是完全二叉树,所以可以考虑用序号递归,模拟后序遍历来求解(只有完全二叉树和满二叉树可以考虑用这种方法求解)

根结点设为1,左节点为2,右节点为3,依次类推,可以发现左节点等于根节点2,右节点等于根节点2+1,由于从1开始编号,所以编号超过节点总数的时候说明没有该节点

代码实现

import java.util.Scanner;

public class Main {
    public static int[] tree;
    public static int n, now;
    public static int []post;
    public static void main(String[] args) {
        Scanner sca=new Scanner(System.in);
         n=sca.nextInt();
        tree=new int[n+1];
        post=new int[n+1];
        
        for (int i = 0; i < n; i++)
        {
            post[i]=sca.nextInt();
        }
        build(1);
        for (int i = 1; i <= n; i++)
        {
            if (i != 1)
                System.out.print(" ");
            System.out.print(tree[i]);
        }
    
    }
    //因为其是完全二叉树(只有完全二叉树和满二叉树才可用该方法)
    //所以除了最后一层不是满的,其它层均是满的
    //有右孩子就必定有左孩子
    //根结点设为1,左节点为2,右节点为3,依次类推,可以发现左节点等于根节点*2,右节点等于根节点*2+1,由于从1开始编号,所以编号超过节点总数的时候说明没有该节点
    public static void build(int root)
    {
        if (root > n)
            return;
        //递归左节点
        build(root * 2);
        //递归右节点
        build(root * 2 + 1);
        tree[root] = post[now++];
    }

}

补充方法,根据完全二叉树的 后序遍历来还原二叉树

private static TreeNode buildTreeT(int xh) {
        if (xh > n) {
            return null;
        }
        TreeNode root = new TreeNode();
        root.left = buildTreeT(xh * 2);
        root.right = buildTreeT(xh * 2 + 1);
        root.val = post[now++];
        return root;
    }

 

posted @ 2022-04-13 16:22  lzstar-A2  阅读(34)  评论(0编辑  收藏  举报