数据结构之二叉树及面试题讲解(二)

简介: 数据结构之二叉树及面试题讲解

数据结构之二叉树及面试题讲解(一)+https://developer.aliyun.com/article/1413553

3,后序遍历

public void postOrder(TreeNode root) {
// 空树 直接返回
        if(root == null) return;
        postOrder(root.lChild);
        postOrder(root.rChild);
        System.out.print(root.val+" ");
    }

https://leetcode.cn/problems/binary-tree-preorder-traversal/submissions/

代码实现

public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if(root == null) return list;
        // 遍历左子树
        List<Integer> leftTree = postorderTraversal(root.left);
        list.addAll(leftTree);
        // 遍历右子树
        List<Integer> rightTree = postorderTraversal(root.right);
        list.addAll(rightTree);
        list.add(root.val);
        return list;
    }

4.层序遍历

 使用队列来模拟实现(自己画图想一下,很简单)

/**
     * 层序遍历  一层一层的遍历  打印
     * 先遇到  先打印  fifo  先进先出  使用队列存储遍历的结点
     * @param root
     */
    // 层序遍历
    public void levelOrder(TreeNode root) {
        if(root == null) return;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()) {
            TreeNode cur = queue.poll();
            System.out.print(cur.val+" ");
            if (cur.lChild != null) {
                queue.offer(cur.lChild);
            }
            if (cur.rChild != null) {
                queue.offer(cur.rChild);
            }
        }
    }

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

public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> ret = new ArrayList<>();
        if(root == null) return ret;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()) {
            List<Integer> tmpList = new ArrayList<>();
            // 记录当前队列中的结点个数  决定了当前层的tmpList存储的结点个数  也方便添加后序的孩子节点
            int size = queue.size();
            while(size > 0) {
                TreeNode cur = queue.poll();
                if(cur.left != null) queue.offer(cur.left);
                if(cur.right != null) queue.offer(cur.right);
                tmpList.add(cur.val);
                size--;
            }
            ret.add(tmpList);
        }
        return ret;
    }

3.二叉树的基本操作

5.求结点个数  

 最基本的思路就是定义一个计数器,遍历每一个结点,遍历的方法可以是前序,中序,后序,层序,下面实现两种:递归实现和子问题思路

注:这里的递归实现采用了前序遍历的方式

/**
     * 求size  遍历每一个结点 设置一个计数器
     */
    public int size = 0;
    public int getSize(TreeNode root) {
// 空树 直接返回  结点数为1
        if(root == null) return 0;
        size++;
        getSize(root.lChild);
        getSize(root.rChild);
        return size;
    }
    // 子问题思路:结点的个数 == 左子树的节点个数+右子树的结点个数+根节点
    public int getSize2(TreeNode root) {
        if(root == null) return 0;
        return getSize2(root.lChild) +
                getSize2(root.rChild) + 1;
    }

6.求叶子节点的个数

 叶子节点即左右孩子都为空的结点,要求叶子节点的个数,需要遍历寻找;

/**
     * 求叶子节点的个数
     * 1.遍历实现  满足左右节点都为空  ++
     * 2.子问题思路:root叶子节点的个数 == 左子树叶子节点的个数+右子树叶子节点的个数
     */
    public int leafSize = 0;
    public int getLeafSize(TreeNode root) {
        // 递归结束条件  这其实是二叉树的一种情况
        // 二叉树有两类  空树  和非空树
        // 空树 没有叶子结点  返回0
        if(root == null) return 0;
        if (root.lChild == null && root.rChild == null) {
            leafSize++;
        }
        getLeafSize(root.lChild);
        getLeafSize(root.rChild);
        return leafSize;
    }
    public int getLeafSize2(TreeNode root) {
        // 子问题思路
        // root叶子节点的个数 == 左子树叶子节点的个数+右子树叶子节点的个数
        if(root == null) return 0;
        if(root.lChild == null && root.rChild == null) return 1;
        return getLeafSize2(root.lChild) + getLeafSize2(root.rChild);
    }

7.求第k层的结点个数

 转化为子问题思路

/**
     * 获取第k层结点的个数
     * 子问题思路:等价于左树第k-1层和右树第k-1层结点的个数
     * 一直走到第k层
     * @param root
     * @param k
     * @return
     */
    public int getKLevelNodeConut(TreeNode root,int k) {
        if(root == null) return 0;
        // 等于1  证明走到了第k层  现在就是第k层的某一个节点
        if(k == 1) return 1;
        return getKLevelNodeConut(root.lChild,k-1) +
                getKLevelNodeConut(root.rChild,k-1);
    }

8.求树的高度

子问题思路:树的高度 = 左树和右树高度的最大值+1

// 这种方法可以通过  递归只计算了一次
    public int getHeight(TreeNode root) {
        // 想好递归条件  最后一定是走到null结点  其高度为0  往回归
        if(root == null) return 0;
        int leftHeight = getHeight(root.lChild);
        int rightHeight = getHeight(root.rChild);
        return leftHeight > rightHeight ? leftHeight+1 : rightHeight+1;
    }

9.判断是否包含某节点

 先判断根节点  再去遍历左子树  左子树包含 直接返回  不包含   遍历右子树

/**
     * 判断是否含有某个值的结点
     */
    public boolean find(TreeNode root,char val) {
        // 为空  直接返回
        if(root == null) return false;
        if(root.val == val) return true;
        // 遍历左子树  如果找到,则flg1为true  直接返回即可  不需要再去遍历右子树
        boolean flg1 = find(root.lChild,val);
        if(flg1) return true;
        // 遍历右子树
        boolean flg2 = find(root.rChild,val);
        if(flg2) return true;
        return false;
    }

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

 利用层序遍历的思路,把当前结点的所有孩子结点都加入(如果孩子节点是null也会被插入),当遇到null时,如果是完全二叉树,则此结点一定是最后一个节点,即queue.size == 0,如果不是完全二叉树,则queue.size != 0

/**
     * 判断是否是完全二叉树
     * 层序遍历的思路  把所有结点的左右孩子节点都存入到queue中  如果遇到null 去判断是否还存在元素
     * 存在 -- 不是完全二叉树
     * @param root
     * @return
     */
    public boolean iscompleteTree(TreeNode root) {
        if(root == null) return true;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            TreeNode cur = queue.poll();
            // 如果queue中存储的是null 它会被存储到queue中  但却不算有效数据个数
            if (cur == null) {
                if(queue.size() != 0) {
                    return false;
                }
            }
            queue.offer(cur.lChild);
            queue.offer(cur.rChild);
        }
        return true;
    }

三.二叉树的相关OJ题目

 二叉树作为面试中常考的题目有一定的难度(且难度不小),需要认真去练习,总结

1.判断两棵树是否相同

https://leetcode.cn/problems/same-tree/submissions/

思路分析:

 这题可以采用子问题思路  先分析判断的思路,先判断结构上是否一致,如果一致,再去判断值是否相同

  • 如果一个为空,一个不为空,结构上不同  返回false
  • 如果两个都为空  返回true
  • 如果结构上完全相同,去判断值是否相同

代码实现

// 先判断当前所在根是否相同  不同  判断左结点  再判断右节点
        // 不同  值不同  一个为空,一个不为空  
        // 相同  值相同  或者两个都为空
        // 一个为空,一个不为空  
        if(p != null && q == null || p == null && q != null) return false;
        // 两个都为空  认为相等
        if(p == null && q == null) return true;
        // 值不同  走到这里说明两个引用都不为空  只需判断值是否相同即可
        if(p.val != q.val) return false;
        return isSameTree(p.left,q.left) && 
                isSameTree(p.right,q.right);

2.另一棵树的子树

 https://leetcode.cn/problems/subtree-of-another-tree/description/

思路分析

  • 先判断root是否是null,为空直接返回false
  • 判断当前根节点是否和subRoot是否是相同的树
  • 再去递归遍历root的左树和右数是否和subRoot是相同的树

代码实现

class Solution {
    private boolean isSameTree(TreeNode p,TreeNode q) {
        if(p == null && q != null || p != null && q == null) return false;
        if(p == null && q == null) return true;
        if(p.val != q.val) return false;
        return isSameTree(p.left,q.left) && 
                isSameTree(p.right,q.right);
    }
    public boolean isSubtree(TreeNode root, TreeNode subRoot) {
        if(root == null ) return false;
        // 判断当前节点是否满足条件
        if(isSameTree(root,subRoot)) return true;
        // 递归遍历左树和右树
        if(isSubtree(root.left,subRoot)) return true;
        if(isSubtree(root.right,subRoot)) return true;
        // 走到这里 说明以上情况都不满足 直接返回false;
        return false;
    }
}

数据结构之二叉树及面试题讲解(三)+https://developer.aliyun.com/article/1413556

目录
相关文章
|
4月前
|
存储 安全 Java
Java 集合面试题从数据结构到 HashMap 源码剖析详解及长尾考点梳理
本文深入解析Java集合框架,涵盖基础概念、常见集合类型及HashMap的底层数据结构与源码实现。从Collection、Map到Iterator接口,逐一剖析其特性与应用场景。重点解读HashMap在JDK1.7与1.8中的数据结构演变,包括数组+链表+红黑树优化,以及put方法和扩容机制的实现细节。结合订单管理与用户权限管理等实际案例,展示集合框架的应用价值,助你全面掌握相关知识,轻松应对面试与开发需求。
198 3
|
7月前
|
存储 算法 Java
算法系列之数据结构-二叉树
树是一种重要的非线性数据结构,广泛应用于各种算法和应用中。本文介绍了树的基本概念、常见类型(如二叉树、满二叉树、完全二叉树、平衡二叉树、B树等)及其在Java中的实现。通过递归方法实现了二叉树的前序、中序、后序和层次遍历,并展示了具体的代码示例和运行结果。掌握树结构有助于提高编程能力,优化算法设计。
195 10
 算法系列之数据结构-二叉树
|
9月前
|
Java C++
【C++数据结构——树】二叉树的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现二叉树的基本运算。​ 相关知识 创建二叉树 销毁二叉树 查找结点 求二叉树的高度 输出二叉树 //二叉树节点结构体定义 structTreeNode{ intval; TreeNode*left; TreeNode*right; TreeNode(intx):val(x),left(NULL),right(NULL){} }; 创建二叉树 //创建二叉树函数(简单示例,手动构建) TreeNode*create
186 12
|
9月前
|
C++
【C++数据结构——树】二叉树的性质(头歌实践教学平台习题)【合集】
本文档介绍了如何根据二叉树的括号表示串创建二叉树,并计算其结点个数、叶子结点个数、某结点的层次和二叉树的宽度。主要内容包括: 1. **定义二叉树节点结构体**:定义了包含节点值、左子节点指针和右子节点指针的结构体。 2. **实现构建二叉树的函数**:通过解析括号表示串,递归地构建二叉树的各个节点及其子树。 3. **使用示例**:展示了如何调用 `buildTree` 函数构建二叉树并进行简单验证。 4. **计算二叉树属性**: - 计算二叉树节点个数。 - 计算二叉树叶子节点个数。 - 计算某节点的层次。 - 计算二叉树的宽度。 最后,提供了测试说明及通关代
166 10
|
9月前
|
存储 算法 测试技术
【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
262 3
|
10月前
|
数据库
数据结构中二叉树,哈希表,顺序表,链表的比较补充
二叉搜索树,哈希表,顺序表,链表的特点的比较
数据结构中二叉树,哈希表,顺序表,链表的比较补充
|
11月前
|
机器学习/深度学习 存储 算法
数据结构实验之二叉树实验基础
本实验旨在掌握二叉树的基本特性和遍历算法,包括先序、中序、后序的递归与非递归遍历方法。通过编程实践,加深对二叉树结构的理解,学习如何计算二叉树的深度、叶子节点数等属性。实验内容涉及创建二叉树、实现各种遍历算法及求解特定节点数量。
259 4
|
11月前
|
C语言
【数据结构】二叉树(c语言)(附源码)
本文介绍了如何使用链式结构实现二叉树的基本功能,包括前序、中序、后序和层序遍历,统计节点个数和树的高度,查找节点,判断是否为完全二叉树,以及销毁二叉树。通过手动创建一棵二叉树,详细讲解了每个功能的实现方法和代码示例,帮助读者深入理解递归和数据结构的应用。
693 8
|
12月前
|
存储 算法 关系型数据库
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
这篇文章主要介绍了多路查找树的基本概念,包括二叉树的局限性、多叉树的优化、B树及其变体(如2-3树、B+树、B*树)的特点和应用,旨在帮助读者理解这些数据结构在文件系统和数据库系统中的重要性和效率。
134 0
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
|
11月前
|
存储 NoSQL Redis
Redis常见面试题:ZSet底层数据结构,SDS、压缩列表ZipList、跳表SkipList
String类型底层数据结构,List类型全面解析,ZSet底层数据结构;简单动态字符串SDS、压缩列表ZipList、哈希表、跳表SkipList、整数数组IntSet