【数据结构Java版】树与二叉树的相关知识全解

目录

一、树型结构

(1)树的定义

(2)树的基本术语

(3)树的存储结构

二、二叉树

(1)二叉树的定义

(2)两种特殊二叉树

1.满二叉树

2.完全二叉树

(3)二叉树的性质

1.公式

2.习题

(4)二叉树的存储

(5)二叉树的基本操作

1.二叉树的遍历之前序遍历

2.二叉树的遍历之中序遍历

3.二叉树的遍历之后序遍历

4.二叉树的遍历之层序遍历 

5. 统计二叉树中结点个数

6.统计二叉树中叶子节点的个数

7.统计二叉树的第K层上的结点个数

8.求一棵二叉树的高度

9.给定一个值,在二叉树中进行查找,返回包含这个值的结点

10.判断是否是完全二叉树

三、二叉树oj题 

(1)检查两颗树是否相同

(2)另一颗树的子树

(3)翻转二叉树

(4)判断一颗二叉树是否是平衡二叉树

(5)对称二叉树

(6)二叉树的构建及遍历

(7)二叉树的分层遍历 

(8)给定一个二叉树, 找到该树中两个指定节点的最近公共祖先 

(9)根据一棵树的前序遍历与中序遍历构造二叉树

(10)根据一棵树的中序遍历与后序遍历构造二叉树

(11)二叉树创建字符串

(12)二叉树前序非递归遍历实现 

(13)二叉树中序非递归遍历实现

(14)二叉树后序非递归遍历实现


一、树型结构

(1)树的定义

        a.树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,(根朝上,而叶朝下)它具有以下的特点:
        b.有一个特殊的结点,称为根结点,根结点没有前驱结点。除根结点外,其余结点被分成M(M > 0)个互不相交的集合T1、T2、......、Tm,其中每一个集合Ti (1 <= i <=m) 又是一棵与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继。
        c.树是递归定义的。树形结构中,子树之间不能有交集,否则就不是树形结构。

591b433957fe4aa78d899211091f56b6.png

(2)树的基本术语

181bb0dbf3fb43678e8c8020cf6e8e42.png

结点的度:一个结点含有子树的个数称为该结点的度; 如上图:A的度为6
树的度:一棵树中,所有结点度的最大值称为树的度; 如上图:树的度为6
叶子结点或终端结点:度为0的结点称为叶结点; 如上图:B、C、H、I...等节点为叶结点
双亲结点或父结点:若一个结点含有子结点,则这个结点称为其子结点的父结点; 如上图:A是B的父结点
孩子结点或子结点:一个结点含有的子树的根结点称为该结点的子结点; 如上图:B是A的孩子结点
根结点:一棵树中,没有双亲结点的结点;如上图:A
结点的层次:从根开始定义起,根为第1层,根的子结点为第2层,以此类推
树的高度或深度:树中结点的最大层次; 如上图:树的高度为4
非终端结点或分支结点:度不为0的结点; 如上图:D、E、F、G...等节点为分支结点
兄弟结点:具有相同父结点的结点互称为兄弟结点; 如上图:B、C是兄弟结点
堂兄弟结点:双亲在同一层的结点互为堂兄弟;如上图:H、I互为兄弟结点
结点的祖先:从根到该结点所经分支上的所有结点;如上图:A是所有结点的祖先
子孙:以某结点为根的子树中任一结点都称为该结点的子孙。如上图:所有结点都是A的子孙
森林:由m(m>=0)棵互不相交的树组成的集合称为森林

(3)树的存储结构

        树结构相对线性表就比较复杂了,要存储表示起来就比较麻烦了,实际中树有很多种表示方式,如:双亲表示法、孩子表示法、孩子双亲表示法、孩子兄弟表示法等等。

相关博客详解:树的三种表示法:双亲表示法、孩子表示法、孩子兄弟表示法_Huberyxiao的博客-CSDN博客_树的双亲表示法

二、二叉树

(1)二叉树的定义

        一棵二叉树是结点的一个有限结合,该集合需满足两个条件:

a.或者为空

b.或者是由一个根节点加上两棵别称为左子树右子树的二叉树组成

e0e755abc35e4b388dea7d8accc46757.png

a. 二叉树不存在度大于2的结点
b.
二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树

任意的二叉树都是由以下几种情况复合而成的:
206d6dca72a0443d96422cc899ebf63e.png

(2)两种特殊二叉树

1.满二叉树

        一棵二叉树,如果每层的结点数都达到最大值,则这棵二叉树就是满二叉树。也就是说,如果一棵二叉树的层数为K,且结点总数是gif.latex?2%5E%7Bk%7D-1 ,则它就是满二叉树。
8280bd93b03941d8b089dff5504b8179.png        

2.完全二叉树

        完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从0至n-1的结点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树。

7a771d06d12240d099bb6ba54281cbcf.png

(3)二叉树的性质

1.公式

a. 若规定根结点的层数为1,则一棵非空二叉树的第i层上最多有gif.latex?2%5E%7Bi-1%7D (i>0)个结点
b. 若规定只有根结点的二叉树的深度为1,则深度为K的二叉树的最大结点数是 gif.latex?2%5E%7Bk%7D-1(k>=0)
c. 对任何一棵二叉树, 如果其叶结点个数为 gif.latex?n_%7B0%7D, 度为2的非叶结点个数为 gif.latex?n_%7B2%7D,则有gif.latex?n_%7B0%7D%3Dn_%7B2%7D&plus;1
d. 具有n个结点的完全二叉树的深度gif.latex?k%3D gif.latex?log_%7B_2%7D%28n&plus;1%29上取整
e. 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的顺序对所有节点从0开始编号,则对于序号为i的结点有:
若i>0,双亲序号:gif.latex?%5Cfrac%7Bi-1%7D%7B2%7D;i=0,i为根结点编号,无双亲结点
gif.latex?2i&plus;1<n,左孩子序号:gif.latex?2i&plus;1,否则无左孩子
gif.latex?2i&plus;2<n,右孩子序号:gif.latex?2i&plus;2,否则无右孩子

2.习题

1. 某满二叉树中共有 399 个结点,其中有 199 个度为 2 的结点,则该二叉树中的叶子结点数为( B)
A 不存在这样的二叉树
B 200
C 198
D 199

13caef8f94e7483dae912dcfc988c5aa.png
2.在具有 2n 个结点的完全二叉树中,叶子结点个数为(A)
A n
B n+1
C n-1
D n/2

50a6fbf68db44f5bb7ece9223d1104ce.png
3.一个具有767个节点的完全二叉树,其叶子节点个数为(B)
A 383
B 384
C 385
D 386

与第三题同理
4.一棵完全二叉树的节点数为531个,那么这棵树的高度为(B )
A 11
B 10
C 8
D 12

(4)二叉树的存储

        二叉树的存储结构分为:顺序存储和类似于链表的链式存储。
        二叉树的链式存储是通过一个一个的节点引用起来的,常见的表示方式有二叉和三叉表示方式,具体如下:

// 孩子表示法
class Node {
int val; // 数据域
Node left; // 左孩子的引用,常常代表左孩子为根的整棵左子树
Node right; // 右孩子的引用,常常代表右孩子为根的整棵右子树
} 
//孩子双亲表示法
class Node {
int val; // 数据域
Node left; // 左孩子的引用,常常代表左孩子为根的整棵左子树
Node right; // 右孩子的引用,常常代表右孩子为根的整棵右子树
Node parent; // 当前节点的根节点
}

以下代码都是使用如下结点定义:

public class TreeNode {
    public int val;
    public TreeNode left;
    public TreeNode right;
    public TreeNode(int val) {
        this.val = val;     // 这个结点中的值是 val
        this.left = null;   // 这个结点的左孩子是 null:不存在 —— 左子树是空树
        this.right = null;  // 这个结点的有孩子是 null;不存在 —— 右子树是空树
    }
}

 在下面代码中除了利用递归思想,还有另一种方法用到队列。代码实现层面,需要把结点和层数打包在一起,作为队列的元素 。代码中如何体现打包呢?使用一个对象。

static class TreeNodeWithLevel {
        public TreeNode node;
        public int level;

        public TreeNodeWithLevel(TreeNode node, int level) {
            this.node = node;
            this.level = level;
        }

        @Override
        public String toString() {
            return String.format("%s-%d", node.toString(), level);//重写toString方法,使打印明确。
        }
    }

(5)二叉树的基本操作

        遍历(Traversal)是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问。访问结点所做的操作依赖于具体的应用问题(比如:打印节点内容、节点内容加1)。 遍历是二叉树上最重要的操作之一,是二叉树上进行其它运算之基础。

        在遍历二叉树时,如果没有进行某种约定,每个人都按照自己的方式遍历,得出的结果就比较混乱,如果按照某种规则进行约定,则每个人对于同一棵树的遍历结果肯定是相同的。如果N代表根节点,L代表根节点的左子树,R代表根节点的右子树,则根据遍历根节点的先后次序有以下遍历方式:
NLR:前序遍历(Preorder Traversal 又先序遍历)——访问根结点--->根的左子树--->根的右子树。
LNR:中序遍历(Inorder Traversal)——根的左子树--->根节点--->根的右子树。
LRN:后序遍历(Postorder Traversal)——根的左子树--->根的右子树--->根节点

871bee916338469098176c2052622043.png

前序遍历结果:1 2 3 4 5 6
中序遍历结果:3 2 1 5 4 6
后序遍历结果:3 1 5 6 4 1

二叉树的遍历分为深度遍历、广度遍历。

深度遍历:前中后序遍历,需要用到栈。隐式用到栈:递归方法。显示用到栈:非递归方法。

广度遍历:层序遍历,需要用到队列。

1.二叉树的遍历之前序遍历

递归:

    public static void preorder(TreeNode root) {
        if (root == null) {
            return;
        }
        System.out.println(root.val);
        preorder(root.left);
        preorder(root.right);
    }

非递归:

public static void preorder非递归(TreeNode root) {
        Deque<TreeNode> stack = new LinkedList<>(); // 使用 Deque 作为栈来使用
        TreeNode cur = root;

        // 循环停止的条件 cur == null && stack.isEmpty()
        // cur == null 的时候,应该处理 栈 中还有结点的右子树了
        // 但 栈 也是 empty,说明所有的右子树都处理
        // 所以可以停止了
        // 反过来,循环继续的条件
        // !(cur == null && stack.isEmpty())
        // 化简 cur != null || stack.isEmpty() == false
        while (cur != null || stack.isEmpty() == false) {
            // 一路朝左走,不管右子树,但需要回溯,所以记录在栈中
            while (cur != null) {
                System.out.println(cur.toString());
                stack.push(cur);
                cur = cur.left;
            }

            // 依次从栈中弹出元素,处理剩下没走的右子树
            TreeNode top = stack.pop();

            // 处理右子树
            cur = top.right;
        }
    }

2.二叉树的遍历之中序遍历

递归:

   public static void inorder(TreeNode root) {
        if (root == null) {
            return;
        }
        inorder(root.left);
        System.out.println(root.val);
        inorder(root.right);
    }

非递归:

// 中序遍历是第二次经过时打印(从左子树回来时打印) -> 从栈里弹出来的时候打印
    public static void inorder非递归(TreeNode root) {
        Deque<TreeNode> stack = new LinkedList<>(); // 使用 Deque 作为栈来使用
        TreeNode cur = root;

        while (cur != null || stack.isEmpty() == false) {
            while (cur != null) {
                // 第一次经过某结点
                stack.push(cur);
                cur = cur.left;
            }

            // 依次从栈中弹出元素,处理剩下没走的右子树
            TreeNode top = stack.pop();
            System.out.println(top);    // 第二次经过某结点

            // 处理右子树
            cur = top.right;
        }
    }

3.二叉树的遍历之后序遍历

递归:

    public static void postorder(TreeNode root) {
        if (root == null) {
            return;
        }
        postorder(root.left);
        postorder(root.right);
        System.out.println(root.val);
    }

非递归:

public static void postorder非递归(TreeNode root) {
        Deque<TreeNode> stack = new LinkedList<>(); // 使用 Deque 作为栈来使用
        TreeNode cur = root;
        TreeNode last = null;   // 记录上次后序遍历经过的结点

        while (cur != null || stack.isEmpty() == false) {
            while (cur != null) {
                // 第一次经过某结点
                stack.push(cur);
                cur = cur.left;
            }

            // 查看栈顶元素
            TreeNode top = stack.peek();
            if (top.right == null) {
                // 右子树为空的情况下,没必要走第三次
                // 换言之:第二次可以看作第三次
                System.out.println(top);    // 后序
                last = top; // last 记录上一次被后序遍历的结点

                stack.pop();
            } else if (top.right == last) {
                // 上一次后序遍历的结点是 top 的右孩子
                // 说明是从 top 的右边来到 top 的
                // 也就是第三次经过 top 结点
                System.out.println(top);    // 后序
                last = top; // last 记录上一次被后序遍历的结点

                stack.pop();
            } else {
                // 说明是从 top 的左边到的 top
                // 第二次经过 top 结点
                // 不后序遍历,而是继续走 top 的右子树
                // 处理右子树
                cur = top.right;
            }
        }
    }

4.二叉树的遍历之层序遍历 

   public static void levelorder(TreeNode root) {
        if (root == null) {
            return;
        }
        // 使用队列而不是栈,没有递归
        // 因为队列中取出元素后需要把结点的左右孩子继续放进去,所以这里队列的元素类型是 TreeNode
        Queue<TreeNode> queue = new LinkedList<>();
        // 首先把根节点放入队列中,此时此刻的层序遍历不会把 null 放到队列中
        // 所以,所以需要考虑 root == null 的情况
        queue.offer(root);

        // 开启循环,直到 queue.isEmpty() == true
        while (queue.isEmpty() == false) {
            // 1. 取出队首元素
            TreeNode node = queue.poll();
            // 断言 node != null
            // 2. 打印结点的值
            System.out.println(node.toString());
            // 3. 依次从左到右把孩子放入队列中,不放 null 进去
            if (node.left != null) {
                queue.offer(node.left);
            }
            if (node.right != null) {
                queue.offer(node.right);
            }
        }
    }

层序遍历打印结点和层数:

  public static void levelOrderButLevel(TreeNode root) {
        if (root == null) {
            return;
        }

        Queue<TreeNodeWithLevel> queue = new LinkedList<>();//见二叉树的存储
        queue.offer(new TreeNodeWithLevel(root, 1));

        while (!queue.isEmpty()) {
            TreeNodeWithLevel tnwl = queue.poll();
            TreeNode node = tnwl.node;
            int level = tnwl.level;
            System.out.println(tnwl);

            if (node.left != null) {
                queue.offer(new TreeNodeWithLevel(node.left, level + 1));
            }

            if (node.right != null) {
                queue.offer(new TreeNodeWithLevel(node.right, level + 1));
            }
        }
    }
public static void levelOrderButLevel2(TreeNode root) {
        if (root == null) {
            return;
        }

        Queue<TreeNode> nodeQueue = new LinkedList<>();
        Queue<Integer> levelQueue = new LinkedList<>();

        nodeQueue.offer(root);
        levelQueue.offer(1);

        // 代码一定维护着 nodeQueue 和 levelQueue 的元素个数一定是一样的
        // 所以判断,只需要判断其中一个队列是 empty 即可
        while (!nodeQueue.isEmpty()) {
            TreeNode node = nodeQueue.poll();
            int level = levelQueue.poll();

            System.out.println(node + "-" + level);

            if (node.left != null) {
                nodeQueue.offer(node.left);
                levelQueue.offer(level + 1);
            }

            if (node.right != null) {
                nodeQueue.offer(node.right);
                levelQueue.offer(level + 1);
            }
        }
    }

下面是层序遍历的升级版:二叉树的层序遍历

 public static List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> ans = new ArrayList<>();
        if (root == null) {
            return ans;
        }

        // 定义两个队列
        Queue<TreeNode> nodeQueue = new LinkedList<>();
        Queue<Integer> levelQueue = new LinkedList<>();

        // 根结点记为第 0 层
        // 把根结点和它对应的层数放入队列中
        nodeQueue.offer(root);
        levelQueue.offer(0);

        while (!nodeQueue.isEmpty()) {
            TreeNode node = nodeQueue.poll();
            int level = levelQueue.poll();

            // 每个结点的 level 就刚好对应 ans 中的下标,根据这个下标,就可以获取到对应的 List<Integer>,这层的 List
            List<Integer> levelList = ans.get(level);
            // 将元素放入对应的 levelList 中(尾插,保证顺序不变)
            levelList.add(node.val);

            // 层序遍历的模板代码
            if (node.left != null) {
                nodeQueue.offer(node.left);
                levelQueue.offer(level + 1);
            }

            if (node.right != null) {
                nodeQueue.offer(node.right);
                levelQueue.offer(level + 1);
            }
        }

        return ans;
    }

5. 统计二叉树中结点个数

递归:

public static int nodeSize;
    /**
     * 获取树中节点的个数:遍历思路
     */
    void size(TreeNode root) {
        if(root==null){
            return ;
        }
        nodeSize++;
        size(root.left);
        size(root.right);
    }
    /**
     * 获取节点的个数:子问题的思路
     *
     * @param root
     * @return
     */
    int size2(TreeNode root) {
        if(root==null) {
            return 0;
        }
        return size2(root.left)+size2(root.right)+1;
    }

队列:

public static int sizeOf(TreeNode root) {
        if (root == null) {
            // 空树的结点个数
            return 0;
        }

        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);

        int size = 0;
        // 每个结点都会被放入队列中
        // 都会被取出来一次
        // 有多少个结点,这个循环就会持续多少次
        while (!queue.isEmpty()) {
            TreeNode node = queue.poll();
            size++; // 打印替换成 size++
            if (node.left != null) {
                queue.offer(node.left);
            }
            if (node.right != null) {
                queue.offer(node.right);
            }
        }

        return size;
    }

6.统计二叉树中叶子节点的个数

递归:

/*
     获取叶子节点的个数:遍历思路
     */
    public static int leafSize = 0;
 
    void getLeafNodeCount1(TreeNode root) {
        if(root==null){
            return;
        }
        if(root.left==null&&root.right==null){
            leafSize++;
        }
        getLeafNodeCount1(root.left);
        getLeafNodeCount1(root.right);
    }
 /*
     获取叶子节点的个数:子问题
     */
    int getLeafNodeCount2(TreeNode root) {
        if (root==null){
            return 0;
        }
        if(root.left==null&&root.right==null){
            return 1;
        }
        return getLeafNodeCount2(root.left)+getLeafNodeCount2(root.right);
    }

队列:

public static int leafSizeOf(TreeNode root) {
        if (root == null) {
            // 空树的叶子结点个数
            return 0;
        }

        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);

        int size = 0;
        // 每个结点都会被放入队列中
        // 都会被取出来一次
        // 有多少个结点,这个循环就会持续多少次
        while (!queue.isEmpty()) {
            TreeNode node = queue.poll();
            // 只有叶子结点时,才 size++
            if (node.left == null && node.right == null) {
                size++; // 打印替换成 size++
            }
            if (node.left != null) {
                queue.offer(node.left);
            }
            if (node.right != null) {
                queue.offer(node.right);
            }
        }

        return size;
    }

7.统计二叉树的第K层上的结点个数

递归:

/*
    获取第K层节点的个数
     */
    int getKLevelNodeCount(TreeNode root, int k) {
        if(root==null){
            return 0;
        }
        if(k==1){
            return 1;
        }
        return getKLevelNodeCount(root.left,k-1)+getKLevelNodeCount(root.right, k-1);
    }

队列:

public static int getKLevelSize(TreeNode root, int k) {
        if (root == null) {
            return 0;
        }

        Queue<TreeNodeWithLevel> queue = new LinkedList<>();
        queue.offer(new TreeNodeWithLevel(root, 1));

        int size = 0;
        while (!queue.isEmpty()) {
            TreeNodeWithLevel tnwl = queue.poll();
            TreeNode node = tnwl.node;
            int level = tnwl.level;
            if (level == k) {
                // 说明是第 k 层了
                size++;
            }

            if (node.left != null) {
                queue.offer(new TreeNodeWithLevel(node.left, level + 1));
            }

            if (node.right != null) {
                queue.offer(new TreeNodeWithLevel(node.right, level + 1));
            }
        }

        return size;
    }

8.求一棵二叉树的高度

递归:

/*
     获取二叉树的高度
     时间复杂度:O(N)
     */
    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; 
    }

队列:

public static int heightOf(TreeNode root) {
        if (root == null) {
            return 0;
        }

        Queue<TreeNodeWithLevel> queue = new LinkedList<>();
        queue.offer(new TreeNodeWithLevel(root, 1));

        int height = -1;
        while (!queue.isEmpty()) {
            TreeNodeWithLevel tnwl = queue.poll();
            TreeNode node = tnwl.node;
            int level = tnwl.level;

            height = level; //后边的值覆盖前面的值

            if (node.left != null) {
                queue.offer(new TreeNodeWithLevel(node.left, level + 1));
            }

            if (node.right != null) {
                queue.offer(new TreeNodeWithLevel(node.right, level + 1));
            }
        }

        // height 就是最后一个 level,也就是最大的 level
        return height;
    }

9.给定一个值,在二叉树中进行查找,返回包含这个值的结点

   // 检测值为value的元素是否存在
    TreeNode find(TreeNode root, char val) {
        if(root==null){
            return null;
        }
       if(root.val==val){
           return root;
       }
       TreeNode left=find(root.left,val);
       if(left!=null){
           return left;
       }
       TreeNode right=find(root.right, val);
       if(right!=null){
           return right;
       }
        return null;
    }

10.判断是否是完全二叉树

public static boolean isCompleteTree(TreeNode root) {
        if (root == null) {
            // 空树是一种完全二叉树
            return true;
        }

        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);

        // 循环停止的条件,从队列中取出的元素是 null
        while (true) {
            TreeNode node = queue.poll();
            if (node == null) {
                break;
            }

            queue.offer(node.left);
            queue.offer(node.right);
        }

        // 检查队列中剩余的元素是否存在 != null 的情况
        // 存在 != null:非完全二叉树
        // 任取 == null:完全二叉树
        // 所以,遍历队列中剩余的元素
        while (!queue.isEmpty()) {
            TreeNode node = queue.poll();
            if (node != null) {
                // 存在 != null:
                return false;
            }
        }

        // 任取 == null:是完全二叉树
        return true;
    }

三、二叉树oj题 

(1)检查两颗树是否相同

100. 相同的树

class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q) {
        if(p==null&&q==null){
            return true;
        }
        if(p==null||q==null){
            return false;
        }
        if(p.val!=q.val){
            return false;
        }else{
            boolean r=isSameTree(p.left,q.left);
            if(r==false){
                return false;
            }else{
                r=isSameTree(p.right,q.right);
                if(r==false){
                    return false;
                }else{
                    return true;
                }
            }
        }
    }
}

(2)另一颗树的子树

572. 另一棵树的子树

class Solution {
    public boolean isSubtree(TreeNode root, TreeNode subRoot) {
        if(subRoot==null){
            return true;
        }
        if(root==null){
            return false;
        }
        if(isSame(root,subRoot)){
            return true;
        }
       return isSubtree(root.left,subRoot)||isSubtree(root.right,subRoot);
    }
     public boolean isSame(TreeNode root, TreeNode subRoot) {
        if(root==null&&subRoot==null){
            return true;
        }
        if(root==null||subRoot==null){
            return false;
        }
        return root.val==subRoot.val
        &&isSame(root.left,subRoot.left)
        &&isSame(root.right,subRoot.right);
    }
}

(3)翻转二叉树

226. 翻转二叉树

class Solution {
    public TreeNode invertTree(TreeNode root) {
        if(root==null){
            return null;
        }
        invertTree(root.left);
        TreeNode tmp=root.left;
        root.left=root.right;
        root.right=tmp;
        
        invertTree(root.right);
        return root;
    }
}

(4)判断一颗二叉树是否是平衡二叉树

110. 平衡二叉树

class Solution {
    public boolean isBalanced(TreeNode root) {
        if(root==null){
            return true;
        }
        if(!isBalanced(root.left)){
            return false;
        }
        if(!isBalanced(root.right)){
            return false;
        }
        if(Math.abs(height(root.left)-height(root.right))>1){
            return false;
        }
        return true;
    }
    public int height(TreeNode root) {
        if(root==null){
            return 0;
        }
        return height(root.left)>height(root.right)?height(root.left)+1:height(root.right)+1;
        
    }
}

(5)对称二叉树

101. 对称二叉树

class Solution {
    public boolean isSymmetric(TreeNode root) {
        if(root==null){
            return true;
        }
        return isSame(root.left,root.right);
    }
    public boolean isSame(TreeNode p,TreeNode q) {
        if(p==null&&q==null){
            return true;
        }
        if(p==null||q==null){
            return false;
        }
        return p.val==q.val&&isSame(p.left,q.right)&&isSame(p.right,q.left);
    }
}

(6)二叉树的构建及遍历

二叉树遍历_牛客题霸_牛客网

import java.util.*;
import java.lang.*;

class TreeNode{
    char val;
    TreeNode left;
    TreeNode right;
    TreeNode(char val){
        this.val=val;
    }
}

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        while(in.hasNext()){
            String str=in.nextLine();
            List <Character>preorderList=toList(str);
            TreeNode node= createTree(preorderList);
            inorder(node);
        } 
    }
    public static List <Character> toList(String str) {
        List <Character> list=new LinkedList<>();
        for(int i=0;i<str.length();i++){
            list.add(str.charAt(i));
        }
        return list;
    }
    public static TreeNode  createTree(List <Character> proderList) {
        if(proderList.size()==0){
            return null;
        }
        char rootval =proderList.remove(0);
        if(rootval=='#'){
            return null;
        }

        TreeNode root =new TreeNode(rootval);

        TreeNode left = createTree(proderList);
        TreeNode right = createTree(proderList);
        root.left=left;
        root.right=right;
        return root;
    
    }
    public static void inorder(TreeNode root) {
        if(root==null){
            return;
        }
        inorder(root.left);
        System.out.print(root.val+" ");
        inorder(root.right);
    }
    
}

(7)二叉树的分层遍历 

102. 二叉树的层序遍历

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> ans=new LinkedList<>();
        Queue<TreeNode> queue=new LinkedList<>();

        if(root==null){
            return ans;
        }
        queue.offer(root);
        while(!queue.isEmpty()){
            List<Integer> level=new LinkedList<>();
            int levelSize=queue.size();
            for(int i=0;i<levelSize;i++){
                TreeNode node=queue.poll();
                level.add(node.val);
                if(node.left!=null){
                    queue.offer(node.left);
                }
                if(node.right!=null){
                    queue.offer(node.right);
                }
            }
            ans.add(level);
        }
        return ans;
    }
}

(8)给定一个二叉树, 找到该树中两个指定节点的最近公共祖先 

236. 二叉树的最近公共祖先

class Solution {
       public boolean contain(TreeNode root, TreeNode target) {
           if(root==null){
               return false;
           }
           if(root==target){
               return true;
           }
           return contain(root.left,target)||contain(root.right,target);
    }
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(p==root||q==root){
            return root;
        }
    
        boolean r1=contain(root.left,p);
        boolean r2=contain(root.left,q);

        if(r1==true&&r2==true){
            return lowestCommonAncestor(root.left,p,q);
        }
        if(r1==false&&r2==false){
            return lowestCommonAncestor(root.right,p,q);
        }
        return root;
    }
}

(9)根据一棵树的前序遍历与中序遍历构造二叉树

105. 从前序与中序遍历序列构造二叉树

class Solution {
    public List<Integer> arrayToList(List<Integer> list,int[] array) {
        for(int i=0;i<array.length;i++){
            list.add(array[i]);
        }
        return list;
    }
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        List<Integer> inorderList=new LinkedList<>();
        List<Integer> preorderList=new LinkedList<>();
        inorderList=arrayToList(inorderList,inorder);
        preorderList=arrayToList(preorderList,preorder);
        return build(preorderList,inorderList);
    }
public TreeNode build(List <Integer> preorderList, List<Integer> inorderList) {
        if(inorderList.size()==0){
            return null;
        }
        int rootVal=preorderList.get(0);
        TreeNode root=new TreeNode(rootVal);
        
        int leftLength=inorderList.indexOf(rootVal);
        List <Integer> leftpreorderList=preorderList.subList(1,leftLength+1);
        List<Integer> leftinorderList=inorderList.subList(0,leftLength);
        TreeNode letfNode=build(leftpreorderList,leftinorderList);

        List <Integer> rightpreorderList=preorderList.subList(leftLength+1,preorderList.size());
        List <Integer> rightinorderList=inorderList.subList(leftLength+1,inorderList.size());
        TreeNode rightNode=build(rightpreorderList,rightinorderList);

        root.left=letfNode;
        root.right=rightNode;
        return root;
    }
}

(10)根据一棵树的中序遍历与后序遍历构造二叉树

106. 从中序与后序遍历序列构造二叉树

class Solution {
    public List<Integer> arrayToList(List<Integer> list,int[] array) {
        for(int i=0;i<array.length;i++){
            list.add(array[i]);
        }
        return list;
    }
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        List<Integer> inorderList=new LinkedList<>();
        List<Integer> postorderList=new LinkedList<>();

        inorderList=arrayToList(inorderList,inorder);
        postorderList=arrayToList(postorderList,postorder);
        return build(inorderList,postorderList);

    }
       public TreeNode build(List <Integer>inorderList, List<Integer> postorderList) {
        if(inorderList.size()==0){
            return null;
        }
        int rootVal=postorderList.get(postorderList.size()-1);
        TreeNode root=new TreeNode(rootVal);
        
        int leftLength=inorderList.lastIndexOf(rootVal);
        List <Integer> leftinorderList=inorderList.subList(0,leftLength);
        List<Integer> leftpostinorderList=postorderList.subList(0,leftLength);
        TreeNode letfNode=build(leftinorderList,leftpostinorderList);

        List <Integer> rightinorderList=inorderList.subList(leftLength+1,inorderList.size());
        List <Integer> rightpostorderList=postorderList.subList(leftLength,postorderList.size()-1);
        TreeNode rightNode=build(rightinorderList,rightpostorderList);

        root.left=letfNode;
        root.right=rightNode;
        return root;
    }
}

(11)二叉树创建字符串

606. 根据二叉树创建字符串

class Solution {
    public String tree2str(TreeNode root) {
        StringBuilder sb=new StringBuilder();
        preOrder(root,sb);
        String str=sb.toString();
        str=str.substring(1,str.length()-1);
        return str;
    }
    public void preOrder(TreeNode root,StringBuilder sb) {
        if(root==null){
            sb.append("()");
            return;
        }
         sb.append("(");
        if(root.left==null&&root.right!=null){

            sb.append(root.val);
            preOrder(root.left,sb);
            preOrder(root.right,sb);         

        }else if(root.left!=null&&root.right==null){
       
            sb.append(root.val);
            preOrder(root.left,sb);

        }else if(root.left==null&&root.right==null){
            sb.append(root.val);
        }else{

            sb.append(root.val);
            preOrder(root.left,sb);
            preOrder(root.right,sb);   
        }
            sb.append(")");

    }
}

(12)二叉树前序非递归遍历实现 

144. 二叉树的前序遍历

class Solution {
 public List<Integer> preorderTraversal(TreeNode root) {

        List<Integer> ans = new ArrayList<>();

        if (root == null) {
            return ans;
        }

        int rootValue = root.val;
        ans.add(rootValue);
        ans.addAll(preorderTraversal(root.left));
        ans.addAll(preorderTraversal(root.right));
        return ans;
    }
}

(13)二叉树中序非递归遍历实现

94. 二叉树的中序遍历

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List <Integer> list=new LinkedList<>();
        if(root==null){
            return list;
        }
        List <Integer> listLeft=new ArrayList<>();
        List <Integer> listRight=new ArrayList<>();
        listLeft=inorderTraversal(root.left);
        list.addAll(listLeft);
        list.add(root.val);
        listRight=inorderTraversal(root.right);
        list.addAll(listRight);
        return list;
    }
}

(14)二叉树后序非递归遍历实现

145. 二叉树的后序遍历

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer>list=new ArrayList<>();
         if(root==null){
            return list;
        }
       
        List<Integer>listLetf=new ArrayList<>();
        List<Integer>listRight=new ArrayList<>();
        listLetf=postorderTraversal(root.left);
        list.addAll(listLetf);
        listRight=postorderTraversal(root.right);
        list.addAll(listRight);
        list.add(root.val);    
        return list;
    }
}

7f7c93db84fb43df905e31f4c6f686c5.png

评论 24
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小熊爱吃软糖吖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值