当前位置: 首页 > news >正文

【数据结构】二叉树全面详解

目录

        1. 树型结构基础

1.1 树的基本概念

1.2 树的关键术语

1.3 树的表示形式

1.4 树的应用

2. 二叉树深度解析

2.1 二叉树概念

2.2 两种特殊的二叉树

2.2.1 满二叉树

2.2.2 完全二叉树

2.3 二叉树的性质

2.4 二叉树的存储

2.4.1 顺序存储

2.4.2 链式存储

2.5 二叉树的基本操作

2.5.1 二叉树遍历

2.5.2 其他基本操作

2.6 二叉树相关OJ题目解析

2.6.1 检查两棵树是否相同

2.6.2 判断子树

2.6.3 翻转二叉树

2.6.4 判断平衡二叉树

2.6.5 对称二叉树

2.6.6 二叉树的最近公共祖先

2.6.7 根据前序和中序遍历构建二叉树

3. 二叉树进阶话题

3.1 非递归遍历实现

3.1.1 前序遍历非递归

3.1.2 中序遍历非递归

3.1.3 后序遍历非递归

3.2 二叉树序列化与反序列化

4.常见面试考点


1. 树型结构基础

1.1 树的基本概念

树是一种非线性的数据结构,由n(n≥0)个有限节点组成的有层次关系的集合。它像一棵倒挂的树,根在上,叶在下。

​核心特点​​:

  • 有一个特殊的根节点,没有前驱节点

  • 除根节点外,其余节点被分成互不相交的子树

  • 每棵子树的根节点有且只有一个前驱,可以有多个后继

  • 树是递归定义的

​重要提示​​:树形结构中,子树之间不能有交集,否则就不是树形结构。

1.2 树的关键术语

术语

说明

示例

​结点的度​

一个结点含有子树的个数

节点A的度为6

​树的度​

树中所有结点度的最大值

树的度为6

​叶子结点​

度为0的结点

B、C、H、I等节点

​父结点​

含有子结点的结点

A是B的父结点

​子结点​

一个结点含有的子树的根结点

B是A的子结点

​根结点​

没有双亲结点的结点

A

​结点的层次​

从根开始定义,根为第1层

根节点在第1层

​树的高度​

树中结点的最大层次

树的高度为4

​扩展概念​​:

  • 非终端结点:度不为0的结点(D、E、F、G等)

  • 兄弟结点:具有相同父结点的结点(B和C)

  • 堂兄弟结点:双亲在同一层的结点(H和I)

  • 结点的祖先:从根到该结点所经分支上的所有结点

  • 子孙:以某结点为根的子树中任一结点

  • 森林:由m(m≥0)棵互不相交的树组成的集合

1.3 树的表示形式

最常用的是​​孩子兄弟表示法​​:

class TreeNode {int value;TreeNode firstChild; // 第一个孩子节点TreeNode nextSibling; // 下一个兄弟节点
}

1.4 树的应用

  • ​文件系统管理​​:目录和文件的层次结构

  • ​组织架构​​:公司部门的层级关系

  • ​家谱系统​​:家族成员的血缘关系

2. 二叉树深度解析

2.1 二叉树概念

一棵二叉树是结点的有限集合,该集合:

  1. 或者为空

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

​重要特性​​:

  • 二叉树不存在度大于2的结点

  • 二叉树的子树有左右之分,次序不能颠倒,因此二叉树是​​有序树​

​二叉树的基本形态​​:

  1. 空树

  2. 只有根节点

  3. 根节点+左子树

  4. 根节点+右子树

  5. 根节点+左子树+右子树

2.2 两种特殊的二叉树

2.2.1 满二叉树
  • 定义:每层的结点数都达到最大值

  • 性质:层数为K的满二叉树,结点总数为2^K - 1

  • 示例:

A/ \B   C/ \ / \D  E F  G
2.2.2 完全二叉树
  • 定义:深度为K的有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从0至n-1的结点一一对应

  • 特点:叶子结点只能出现在最下两层,且最底层叶子结点都靠左排列

  • 示例:

A/ \B   C/ \ /D  E F

2.3 二叉树的性质

  1. 第i层最多有2^(i-1)个结点(i>0)

  2. 深度为K的二叉树最大结点数是2^K - 1(K≥0)

  3. 对于任何二叉树:叶子结点数n₀ = 度为2的非叶结点数n₂ + 1

  4. 具有n个结点的完全二叉树的深度k为⌈log₂(n+1)⌉

  5. 对于完全二叉树编号为i的结点:

    • 父结点序号:(i-1)/2 (i>0)

    • 左孩子序号:2i+1 (如果2i+1<n)

    • 右孩子序号:2i+2 (如果2i+2<n)

2.4 二叉树的存储

2.4.1 顺序存储

使用数组存储,适合完全二叉树:

// 对于完全二叉树,可以用数组高效存储
int[] tree = new int[n];
// 节点i的父节点:tree[(i-1)/2]
// 节点i的左孩子:tree[2*i+1]
// 节点i的右孩子:tree[2*i+2]
2.4.2 链式存储
// 孩子表示法
class Node {int val;Node left;  // 左子树Node right; // 右子树
}// 孩子双亲表示法
class Node {int val;Node left;Node right;Node parent; // 父节点
}

2.5 二叉树的基本操作

2.5.1 二叉树遍历

​1. 前序遍历(NLR)​

void preOrder(Node root) {if (root == null) return;System.out.print(root.val + " "); // 访问根节点preOrder(root.left);              // 遍历左子树preOrder(root.right);             // 遍历右子树
}

​2. 中序遍历(LNR)​

void inOrder(Node root) {if (root == null) return;inOrder(root.left);              // 遍历左子树System.out.print(root.val + " "); // 访问根节点inOrder(root.right);             // 遍历右子树
}

​3. 后序遍历(LRN)​

void postOrder(Node root) {if (root == null) return;postOrder(root.left);             // 遍历左子树postOrder(root.right);            // 遍历右子树System.out.print(root.val + " "); // 访问根节点
}

​4. 层次遍历​

void levelOrder(Node root) {if (root == null) return;Queue<Node> queue = new LinkedList<>();queue.offer(root);while (!queue.isEmpty()) {Node node = queue.poll();System.out.print(node.val + " ");if (node.left != null) queue.offer(node.left);if (node.right != null) queue.offer(node.right);}
}
2.5.2 其他基本操作
// 1. 获取节点个数
int size(Node root) {if (root == null) return 0;return 1 + size(root.left) + size(root.right);
}// 2. 获取叶子节点个数
int getLeafNodeCount(Node root) {if (root == null) return 0;if (root.left == null && root.right == null) return 1;return getLeafNodeCount(root.left) + getLeafNodeCount(root.right);
}// 3. 获取第K层节点个数
int getKLevelNodeCount(Node root, int k) {if (root == null) return 0;if (k == 1) return 1;return getKLevelNodeCount(root.left, k-1) + getKLevelNodeCount(root.right, k-1);
}// 4. 获取二叉树高度
int getHeight(Node root) {if (root == null) return 0;return 1 + Math.max(getHeight(root.left), getHeight(root.right));
}// 5. 查找值为val的节点
Node find(Node root, int val) {if (root == null) return null;if (root.val == val) return root;Node left = find(root.left, val);if (left != null) return left;return find(root.right, val);
}

2.6 二叉树相关OJ题目解析

2.6.1 检查两棵树是否相同
public boolean isSameTree(Node p, Node q) {if (p == null && q == null) return true;if (p == null || q == null) return false;if (p.val != q.val) return false;return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
}
2.6.2 判断子树
public boolean isSubtree(Node root, Node subRoot) {if (root == null) return false;if (isSameTree(root, subRoot)) return true;return isSubtree(root.left, subRoot) || isSubtree(root.right, subRoot);
}
2.6.3 翻转二叉树
public Node invertTree(Node root) {if (root == null) return null;Node left = invertTree(root.left);Node right = invertTree(root.right);root.left = right;root.right = left;return root;
}
2.6.4 判断平衡二叉树
public boolean isBalanced(Node root) {return checkHeight(root) != -1;
}private int checkHeight(Node root) {if (root == null) return 0;int leftHeight = checkHeight(root.left);if (leftHeight == -1) return -1;int rightHeight = checkHeight(root.right);if (rightHeight == -1) return -1;if (Math.abs(leftHeight - rightHeight) > 1) return -1;return 1 + Math.max(leftHeight, rightHeight);
}
2.6.5 对称二叉树
public boolean isSymmetric(Node root) {if (root == null) return true;return isMirror(root.left, root.right);
}private boolean isMirror(Node t1, Node t2) {if (t1 == null && t2 == null) return true;if (t1 == null || t2 == null) return false;if (t1.val != t2.val) return false;return isMirror(t1.left, t2.right) && isMirror(t1.right, t2.left);
}
2.6.6 二叉树的最近公共祖先
public Node lowestCommonAncestor(Node root, Node p, Node q) {if (root == null || root == p || root == q) return root;Node left = lowestCommonAncestor(root.left, p, q);Node right = lowestCommonAncestor(root.right, p, q);if (left != null && right != null) return root;return left != null ? left : right;
}
2.6.7 根据前序和中序遍历构建二叉树
public Node buildTree(int[] preorder, int[] inorder) {return build(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1);
}private Node build(int[] preorder, int preStart, int preEnd,int[] inorder, int inStart, int inEnd) {if (preStart > preEnd || inStart > inEnd) return null;int rootVal = preorder[preStart];Node root = new Node(rootVal);int rootIndex = 0;for (int i = inStart; i <= inEnd; i++) {if (inorder[i] == rootVal) {rootIndex = i;break;}}int leftSize = rootIndex - inStart;root.left = build(preorder, preStart + 1, preStart + leftSize,inorder, inStart, rootIndex - 1);root.right = build(preorder, preStart + leftSize + 1, preEnd,inorder, rootIndex + 1, inEnd);return root;
}

3. 二叉树进阶话题

3.1 非递归遍历实现

3.1.1 前序遍历非递归
public List<Integer> preorderTraversal(Node root) {List<Integer> result = new ArrayList<>();if (root == null) return result;Stack<Node> stack = new Stack<>();stack.push(root);while (!stack.isEmpty()) {Node node = stack.pop();result.add(node.val);if (node.right != null) stack.push(node.right);if (node.left != null) stack.push(node.left);}return result;
}
3.1.2 中序遍历非递归
public List<Integer> inorderTraversal(Node root) {List<Integer> result = new ArrayList<>();Stack<Node> stack = new Stack<>();Node current = root;while (current != null || !stack.isEmpty()) {while (current != null) {stack.push(current);current = current.left;}current = stack.pop();result.add(current.val);current = current.right;}return result;
}
3.1.3 后序遍历非递归
public List<Integer> postorderTraversal(Node root) {List<Integer> result = new ArrayList<>();if (root == null) return result;Stack<Node> stack1 = new Stack<>();Stack<Node> stack2 = new Stack<>();stack1.push(root);while (!stack1.isEmpty()) {Node node = stack1.pop();stack2.push(node);if (node.left != null) stack1.push(node.left);if (node.right != null) stack1.push(node.right);}while (!stack2.isEmpty()) {result.add(stack2.pop().val);}return result;
}

3.2 二叉树序列化与反序列化

// 序列化
public String serialize(Node root) {if (root == null) return "null";return root.val + "," + serialize(root.left) + "," + serialize(root.right);
}// 反序列化
public Node deserialize(String data) {Queue<String> queue = new LinkedList<>(Arrays.asList(data.split(",")));return buildTree(queue);
}private Node buildTree(Queue<String> queue) {String val = queue.poll();if (val.equals("null")) return null;Node node = new Node(Integer.parseInt(val));node.left = buildTree(queue);node.right = buildTree(queue);return node;
}

4. 常见面试考点

  1. 二叉树的各种遍历算法(递归和非递归)

  2. 二叉树的性质和相关计算

  3. 二叉树的构建和重构

  4. 二叉树与其他数据结构的结合

  5. 二叉树在实际问题中的应用

http://www.dtcms.com/a/406197.html

相关文章:

  • 信号处理与系统设计,第二节课笔记
  • 设计模式(C++)详解——解释器模式(2)
  • Spring Cloud构建分布式微服务架构的完整指南
  • php网站做多久郑州建设网
  • jsp网站开发的使用表格电子商务网站建设的核心是
  • 快速将多个PPT、PPTX幻灯片统一转换成浏览器能直接打开的HTML网页文件
  • IROS 2025将于10月在中国杭州举办,爱迪斯通携手机器人训练与遥操作专家XSENS、HAPTION参展
  • 后海做网站公司网址搜索引擎入口
  • Java之链表
  • IDEA 高效配置指南:从基础到进阶的设置全解析
  • 用 SeaTunnel 同步 MySQL 到 Doris:全量增量 + SQL 过滤
  • C++项目:仿muduo库高并发服务器--------Any类的实现
  • ELK 企业级日志分析系统实战教程
  • 驻马店怎么建设自己的网站wordpress 导出到pdf
  • 网站建设成本表一般什么行业做网站的多
  • 阳台光伏、储能系统再升级!双路电能表,您家能源的“智能管家”
  • 【Unity 入门教程】四、如何制作一个 Perfab
  • 浅谈高校门户网站建设的规范标准找做废薄膜网站
  • Word和WPS文字中的题注没有更新?全选按F9刷新
  • Spring Boot集群 集成Nginx配置:负载均衡+静态资源分离实战
  • 本地生活软件开发指南:从用户需求到商业闭环的实战逻辑
  • 建设网站需要租赁主机吗重庆模板建站代理
  • CSP-J/S初赛赛后总结
  • Leetcode 208. 实现 Trie (前缀树)
  • 国际型网站建设wordpress换网址插件
  • Dlib+OpenCV 人脸轮廓绘制
  • Spring Boot 整合 MySQL 和 Druid
  • 基于 STM32 的智能马桶控制系统设计与实现
  • SpringCloud 项目阶段九:Kafka 接入实战指南 —— 从基础概念、安装配置到 Spring Boot 实战及高可用设计
  • 徐州企业建站模板一个网站的制作过程