数据结构 | 二叉树
概念辨析
遍历逻辑
- DFS:前中后序遍历的逻辑可以借助栈使用递归的方式
- BFS:一般使用队列来实现(先进先出)
解题模式
- 是否可以通过遍历一遍二叉树得到答案?如果可以,用一个
traverse
函数配合外部遍历来实现 ————「遍历」思维模式 - 是否可以定义一个递归函数,通过子问题(子树)的答案推导出原问题的答案?如果可以,写出这个递归函数的定义,并充分利用这个函数的返回值,————「分解问题」思维模式
如果单独抽出一个二叉树节点,它需要做什么事情?需要在什么时候(前/中/后序位置)做?其他的节点无需操心,递归函数会帮你在所有节点上执行相同的操作。
二叉树的所有问题,就是让你在前中后序位置注入巧妙的代码逻辑,去达到自己的目的,你只需要单独思考每一个节点应该做什么,其他的不用你管,抛给二叉树遍历框架,递归会在所有节点上做相同的操作
二叉树递归模板
void traverse(TreeNode root) { if (root == null) { return; } // 前序位置 traverse(root.left); // 中序位置 traverse(root.right); // 后序位置 }
主类
节点是组成部件,树构建节点之间的逻辑关系。不管是树结构也好,还是链表结构也好,头部节点是寻找整个结构最至关重要的部件,是访问的入口,链表最重要的就是头结点,数组也是。
public class TreeNode<T> { T val; TreeNode<T> left; TreeNode<T> right; TreeNode(T value) { this.val = value; this.left = null; this.right = null; } }
前序/中序/后序
public class BinaryTree<T extends Comparable<T>> { private TreeNode<T> root; public BinaryTree() { this.root = null; } public void insert(T value) { if (null == root) { root = new TreeNode<>(value); } else { // TODO insertRecursive(root,value) insertRecursive(root,value); } } /** * 随机插入节点 * @param currentNode * @param value */ private void insertInto(TreeNode<T> currentNode, T value) { if (Math.random() < 0.5) { if (currentNode.left == null) { currentNode.left = new TreeNode<>(value); } else { insertInto(currentNode.left, value); } } else { if (currentNode.right == null) { currentNode.right = new TreeNode<>(value); } else { insertInto(currentNode.right, value); } } } /** * 递归插入 二叉搜索树 * @param currentNode * @param value */ private void insertRecursive(TreeNode<T> currentNode, T value) { if (value.compareTo(currentNode.val) < 0) { if (currentNode.left == null) { currentNode.left = new TreeNode<>(value); } else { insertRecursive(currentNode.left, value); } } else { if (currentNode.right == null) { currentNode.right = new TreeNode<>(value); } else { insertRecursive(currentNode.right, value); } } } /** * 递归先序遍历 */ public void preorderTraversal() { // TODO preorderTraversalRecursive(root) preorderTraversalRecursive(root); } private void preorderTraversalRecursive(TreeNode<T> node) { if (null != node) { System.out.print(node.val + " "); preorderTraversalRecursive(node.left); preorderTraversalRecursive(node.right); } } /** * 递归中序遍历 */ public void inorderTraversal() { // TODO inorderTraversalRecursive(root) inorderTraversalRecursive(root); } private void inorderTraversalRecursive(TreeNode<T> node) { if (null != node) { inorderTraversalRecursive(node.left); System.out.print(node.val + " "); inorderTraversalRecursive(node.right); } } /** * 递归后序遍历 */ public void postorderTraversal() { // TODO postorderTraversalRecursive(root) postorderTraversalRecursive(root); } private void postorderTraversalRecursive(TreeNode<T> node) { if (null != node) { postorderTraversalRecursive(node.left); postorderTraversalRecursive(node.right); System.out.print(node.val + " "); } } /** * 迭代前序遍历 */ public void iterativePreorderTraversal() { Stack<TreeNode<T>> stack = new Stack<>(); TreeNode<T> current = root; while (current != null || !stack.isEmpty()) { while (current != null) { System.out.print(current.val + " "); stack.push(current); current = current.left; } current = stack.pop(); current = current.right; } } /** * 迭代中序遍历 */ public void iterativeInorderTraversal() { Stack<TreeNode<T>> stack = new Stack<>(); TreeNode<T> current = root; while (current != null || !stack.isEmpty()) { while (current != null) { stack.push(current); current = current.left; } current = stack.pop(); System.out.print(current.val + " "); current = current.right; } } /** * 迭代后序遍历 */ public void iterativePostorderTraversal() { Stack<TreeNode<T>> stack1 = new Stack<>(); Stack<TreeNode<T>> stack2 = new Stack<>(); TreeNode<T> current = root; if (current != null) { stack1.push(current); } while (!stack1.isEmpty()) { current = stack1.pop(); stack2.push(current); if (current.left != null) { stack1.push(current.left); } if (current.right != null) { stack1.push(current.right); } } while (!stack2.isEmpty()) { System.out.print(stack2.pop().val + " "); } } }
测试类
public class BinaryTreeTest { @Test public void test_BinaryTree() { BinaryTree<Integer> tree = new BinaryTree<>(); tree.insert(10); tree.insert(5); tree.insert(15); tree.insert(3); tree.insert(7); tree.insert(12); tree.insert(18); System.out.println("Preorder traversal: "); tree.preorderTraversal(); System.out.println(); System.out.println("Iterative Preorder traversal: "); tree.iterativePreorderTraversal(); System.out.println(); System.out.println("===================================="); System.out.println("Inorder traversal: "); tree.inorderTraversal(); System.out.println(); System.out.println("Iterative Inorder traversal"); tree.iterativeInorderTraversal(); System.out.println(); System.out.println("===================================="); System.out.println("Postorder traversal: "); tree.postorderTraversal(); System.out.println(); System.out.println("Iterative Postorder traversal"); tree.iterativePostorderTraversal(); System.out.println(); } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异