数据结构 | 二叉树

概念辨析

遍历逻辑

  • DFS:前中后序遍历的逻辑可以借助栈使用递归的方式
  • BFS:一般使用队列来实现(先进先出)

解题模式

参考源

  1. 是否可以通过遍历一遍二叉树得到答案?如果可以,用一个traverse函数配合外部遍历来实现 ————「遍历」思维模式
  2. 是否可以定义一个递归函数,通过子问题(子树)的答案推导出原问题的答案?如果可以,写出这个递归函数的定义,并充分利用这个函数的返回值,————「分解问题」思维模式

如果单独抽出一个二叉树节点,它需要做什么事情?需要在什么时候(前/中/后序位置)做?其他的节点无需操心,递归函数会帮你在所有节点上执行相同的操作。

二叉树的所有问题,就是让你在前中后序位置注入巧妙的代码逻辑,去达到自己的目的,你只需要单独思考每一个节点应该做什么,其他的不用你管,抛给二叉树遍历框架,递归会在所有节点上做相同的操作

二叉树递归模板

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();
}
}
posted @   Neking  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
点击右上角即可分享
微信分享提示