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

二叉树问题讨论(部分内容待补充)

 一,判断两颗树是否相同

(一)核心案例

1,相同树案例

两颗树结构完全一致,并且对应节点值完全相同。说人话就是长得一模一样。

2,结构不同案例

树 1“根节点 1,左子节点 2”,树 2“根节点 1,右子节点 2”,结构不同,非相同树

3,值不同案例

就是结构一样但是二叉树所存储的值不同

public boolean isSameTree(TreeNode p,TreeNode q){//情况1,一个为空另一个不为空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);} 

二,判断一颗树是否为另一颗树的子树

核心案例二

1,递归思想:将判断整棵树是否相同拆解为判断根节点是否相同拆解为

      a.判断根节点是否相同b.左子树是否相同c.右子树是否相同。

通过递归逐层验证。

2,结构优先判断:先通过节点是否为空判断结构是否一致,在判断节点值是否相同,避免无效的数值比较。

3,边界处理:空树是特殊情况,两个空树视为相同,一个空树一个非空视为不同,覆盖所有的边界场景

public blooean isSameTree(TreeNode p,TreeNode q){if((p==null&&q=!=null)||(q==null&&p=!=null)){return false;}if(p==null&&q==null){return false;
}            if(p.val!=q.vall){return false;
} return  isSameTree(p.left, q.left) && isSameTree(p.right, q.right);}public boolean isSubtree(TreeeNode root ,TreeNode subRoot){if (root==null){return false;     
}       if( isSameTree(root ,subRoot)){return true;}return isSubtree(root.left,subRoot)&&isSubtree(root.right,subRoot);}

三,反转二叉树

核心案例

1,基础反转案例,原树为 “根节点 4,左子节点 2(左子节点 1,右子节点 3),右子节点 7(左子节点 6,右子节点 9)”,反转后为 “根节点 4,左子节点 7(左子节点 9,右子节点 6),右子节点 2(左子节点 3,右子节点 1)”,每个节点的左右子树完全交换。

2,空树、单位节点树案例,空树反转后仍为空树;单节点树(仅根节点 5)反转后仍为自身,无左右子树可交换。

参考代码

public TreeNode invertTree(TreeNode root){if (root ==null){return null;}if (root.left == null && root.right == null) {return root;}TreeNode temp=root.left;root.left=root.right;root.right=temp;invertTree(root.left);// 反转右子树invertTree(root.right);// 反转左子树return root;}

四,判断二叉树是否对称‘

核心案例

1,对称数案例:树为 “根节点 1,左子节点 2(左子节点 3,右子节点 4),右子节点 2(左子节点 4,右子节点 3)”,以根节点为中线,左子树的左节点与右子树的右节点相同(3 和 3),左子树的右节点与右子树的左节点相同(4 和 4),整体对称。

2,非对称树案例(结构不对称):树为 “根节点 1,左子节点 2(右子节点 3),右子节点 2(右子节点 3)”,左子树的左为空,右子树的右为空,但左子树的右与右子树的右结构不匹配,非对称。

3,非对称树案例(值不对称)树为 “根节点 1,左子节点 2(左子节点 3),右子节点 2(左子节点 4)”,结构对称但对应节点值(3 和 4)不同,非对称。

public boolean isMirror(TreeNode leftTree,TreeNode rightTree){if((leftTree==null&&rightTree!=null)||(rightTree==null&&leftTree!=null)){return false;
}if (leftTree==null&&rightTtree==null){return true;}if(leftTee.val!=rightTree.val){return false;
}   return isMirror( leftTree.left, rightTree.right)&&isMirror(leftTree.right, rightTree.left);
}
public boolean isSymmetric(Tree  root){if(root ==null){return true;}return  isMirror(root.left, root.right);}

五,判断二叉树是否平衡

核心案例

1,平衡树案例

树为 “根节点 3,左子节点 9,右子节点 20(左子节点 15,右子节点 7)”,每个节点的左右子树高度差均≤1(根节点左高 1、右高 2,差 1;20 左高 1、右高 1,差 0;9 无后代,差 0),为平衡树。

2,非平衡树案例

树为 “根节点 1,左子节点 2(左子节点 3,左子节点 4),右子节点 2”,根节点左子树高度 3、右子树高度 1,差 2>1,非平衡树。

 public int getHeight (TreeNode root){if(root==null){return 0;   
}return 1+Math.max(getHeight(root.left),getHeight(root.right));
}public blooean isBalanced(TreeNode root){if(root==null){return true;
}int leftHeight = getHeight(root.left);int rightHeight = getHeight(root.right);return Math.abs(leftHeight -rightHeight)<=1&& isBalanced(root.left)&& isBalanced(root.right);}

优化后的代码

// 辅助方法:求高度的同时判断是否平衡,不平衡返回-1
private int getHeightAndCheckBalance(TreeNode root) {if (root == null) {return 0;}// 求左子树高度,若左子树不平衡,直接返回-1int leftHeight = getHeightAndCheckBalance(root.left);if (leftHeight == -1) {return -1;}// 求右子树高度,若右子树不平衡,直接返回-1int rightHeight = getHeightAndCheckBalance(root.right);if (rightHeight == -1) {return -1;}// 若当前节点不平衡,返回-1;否则返回当前节点的高度if (Math.abs(leftHeight - rightHeight) > 1) {return -1;}return 1 + Math.max(leftHeight, rightHeight);
}public boolean isBalanced(TreeNode root) {// 若返回值≠-1,说明树平衡return getHeightAndCheckBalance(root) != -1;
}

六 ,二叉树的创建

import java.util.Scanner;public class CreatTree {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);while (scanner.hasNextLine()) {String str = scanner.nextLine();int[] index = {0};  // 用数组存储索引,解决递归中索引共享问题TreeNode root = creatNode(str, index);  // 传入索引参数inorderNode(root);  // 修正方法名拼写(inoredrNode→inorderNode)}scanner.close();  // 补充关闭资源}public static TreeNode creatNode(String str, int[] index) {TreeNode root = null;// 避免索引越界if (index[0] >= str.length()) {return null;}// 读取当前索引位置的字符char c = str.charAt(index[0]);if (c != '#') {  // 非空节点root = new TreeNode(c);index[0]++;root.left = creatNode(str, index);root.right = creatNode(str, index);} else {index[0]++;}return root;}public static void inorderNode(TreeNode root) {if (root == null) {return;}inorderNode(root.left);System.out.print(root.val + " ");inorderNode(root.right);}
}
public class TreeNode {Character val;TreeNode left;TreeNode right;public TreeNode( char val) {this.val = val;left=null;right=null;}
}

基于栈的实现方案(逆序入站哦)

import java.util.Scanner;
import java.util.Stack;public class CreatTree {static class TreeNode {char val;TreeNode left;TreeNode right;TreeNode(char val) {this.val = val;left = null;right = null;}}public static void main(String[] args) {Scanner scanner = new Scanner(System.in);while (scanner.hasNextLine()) {String str = scanner.nextLine();// 将字符串转换为栈(按顺序入栈,栈顶为第一个字符)Stack<Character> stack = new Stack<>();for (int i = str.length() - 1; i >= 0; i--) { // 逆序入栈,保证弹出顺序与字符串一致stack.push(str.charAt(i));}TreeNode root = creatNode(stack); // 传入栈构建树inorderNode(root);System.out.println(); // 换行区分多次输入}scanner.close();}// 用栈构建二叉树,每次弹出栈顶元素处理public static TreeNode creatNode(Stack<Character> stack) {// 栈为空,返回空节点if (stack.isEmpty()) {return null;}// 弹出栈顶元素(当前待处理字符)char c = stack.pop();if (c == '#') { // '#'表示空节点return null;}// 非空节点:创建节点,递归构建左右子树(栈已弹出当前字符,后续处理下一个)TreeNode root = new TreeNode(c);root.left = creatNode(stack);  // 先构建左子树(栈顶已更新为下一个字符)root.right = creatNode(stack); // 再构建右子树return root;}// 中序遍历(递归,也可改为栈实现的非递归遍历)public static void inorderNode(TreeNode root) {if (root == null) {return;}inorderNode(root.left);System.out.print(root.val + " ");inorderNode(root.right);}
}

七,二叉树的分层遍历 

import java.util.*;// 二叉树节点定义
class TreeNode {int val;TreeNode left;TreeNode right;TreeNode(int x) {val = x;left = null;right = null;}
}public class BinaryTreeLevelOrderTraversal {public List<List<Integer>> levelOrder(TreeNode root) {List<List<Integer>> result = new ArrayList<>();if (root == null) {return result;}// 使用队列实现层次遍历Queue<TreeNode> queue = new LinkedList<>();queue.offer(root);while (!queue.isEmpty()) {// 当前层的节点数量int levelSize = queue.size();List<Integer> currentLevel = new ArrayList<>();// 遍历当前层的所有节点for (int i = 0; i < levelSize; i++) {TreeNode node = queue.poll();currentLevel.add(node.val);// 将下一层的节点加入队列if (node.left != null) {queue.offer(node.left);}if (node.right != null) {queue.offer(node.right);}}// 将当前层的结果加入总结果result.add(currentLevel);}return result;}// 测试代码public static void main(String[] args) {// 构建示例二叉树TreeNode root = new TreeNode(3);root.left = new TreeNode(9);root.right = new TreeNode(20);root.right.left = new TreeNode(15);root.right.right = new TreeNode(7);BinaryTreeLevelOrderTraversal solution = new BinaryTreeLevelOrderTraversal();List<List<Integer>> result = solution.levelOrder(root);// 打印结果for (List<Integer> level : result) {System.out.println(level);}}
}

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

class TreeNode {int val;TreeNode left;TreeNode right;TreeNode(int x) {val = x;}
}public class LowestCommonAncestor {public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {// 边界条件:若root为null,或root是p/q,直接返回rootif (root == null || root == p || root == q) {return root;}// 递归查找左子树TreeNode left = lowestCommonAncestor(root.left, p, q);// 递归查找右子树TreeNode right = lowestCommonAncestor(root.right, p, q);// 左右子树分别找到p和q,当前节点是LCAif (left != null && right != null) {return root;}// 只在左子树找到,返回左子树结果// 只在右子树找到,返回右子树结果return left != null ? left : right;}
}
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.Stack;public class LowestCommonAncestor {public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {// 存储节点与其父节点的映射Map<TreeNode, TreeNode> parentMap = new HashMap<>();// 根节点没有父节点parentMap.put(root, null);// 用栈遍历树,记录所有节点的父节点Stack<TreeNode> stack = new Stack<>();stack.push(root);while (!stack.isEmpty()) {TreeNode node = stack.pop();// 记录左子树的父节点if (node.left != null) {parentMap.put(node.left, node);stack.push(node.left);}// 记录右子树的父节点if (node.right != null) {parentMap.put(node.right, node);stack.push(node.right);}}// 记录p的所有祖先(包括p自身)Set<TreeNode> pAncestors = new HashSet<>();while (p != null) {pAncestors.add(p);p = parentMap.get(p); // 向上移动到父节点}// 从q向上追溯,第一个出现在p的祖先集合中的节点即为LCAwhile (q != null) {if (pAncestors.contains(q)) {return q;}q = parentMap.get(q); // 向上移动到父节点}return null; // 理论上不会走到这里(题目保证p和q在树中)}
}

九,根据一棵树的前序遍历与中序遍历构造二叉树。

import java.util.HashMap;
import java.util.Map;class TreeNode {int val;TreeNode left;TreeNode right;TreeNode(int x) {val = x;}
}public class BuildTree {// 存储中序遍历中值与索引的映射,加速查找private Map<Integer, Integer> inorderMap;// 前序遍历数组private int[] preorder;public TreeNode buildTree(int[] preorder, int[] inorder) {this.preorder = preorder;inorderMap = new HashMap<>();// 构建中序遍历的映射表for (int i = 0; i < inorder.length; i++) {inorderMap.put(inorder[i], i);}// 递归构造二叉树return build(0, preorder.length - 1, 0, inorder.length - 1);}/*** 递归构建二叉树* @param preStart 前序遍历起始索引* @param preEnd   前序遍历结束索引* @param inStart  中序遍历起始索引* @param inEnd    中序遍历结束索引* @return 构建的子树的根节点*/private TreeNode build(int preStart, int preEnd, int inStart, int inEnd) {// 终止条件:索引越界if (preStart > preEnd || inStart > inEnd) {return null;}// 前序遍历的第一个元素是当前根节点int rootVal = preorder[preStart];TreeNode root = new TreeNode(rootVal);// 找到根节点在中序遍历中的位置int rootIndexInOrder = inorderMap.get(rootVal);// 左子树的节点数量int leftSize = rootIndexInOrder - inStart;// 递归构建左子树root.left = build(preStart + 1,                // 左子树前序起始索引preStart + leftSize,         // 左子树前序结束索引inStart,                     // 左子树中序起始索引rootIndexInOrder - 1         // 左子树中序结束索引);// 递归构建右子树root.right = build(preStart + leftSize + 1,     // 右子树前序起始索引preEnd,                      // 右子树前序结束索引rootIndexInOrder + 1,        // 右子树中序起始索引inEnd                        // 右子树中序结束索引);return root;}// 测试代码public static void main(String[] args) {int[] preorder = {3, 9, 20, 15, 7};int[] inorder = {9, 3, 15, 20, 7};BuildTree solution = new BuildTree();TreeNode root = solution.buildTree(preorder, inorder);// 可通过前序/中序遍历验证结果}
}

十,二叉树创建字符串。

class TreeNode {int val;TreeNode left;TreeNode right;TreeNode(int x) {val = x;}
}public class Tree2Str {public String tree2str(TreeNode root) {// 空树直接返回空字符串if (root == null) {return "";}// 叶子节点直接返回其值if (root.left == null && root.right == null) {return String.valueOf(root.val);}// 只有右子树时,左子树需要用空括号表示if (root.left == null) {return root.val + "()(" + tree2str(root.right) + ")";}// 只有左子树时,右子树可以省略括号if (root.right == null) {return root.val + "(" + tree2str(root.left) + ")";}// 左右子树都存在时,都需要用括号包裹return root.val + "(" + tree2str(root.left) + ")" + "(" + tree2str(root.right) + ")";}// 测试代码public static void main(String[] args) {// 构建示例二叉树TreeNode root = new TreeNode(1);root.left = new TreeNode(2);root.right = new TreeNode(3);root.left.left = new TreeNode(4);Tree2Str solution = new Tree2Str();System.out.println(solution.tree2str(root)); // 输出: 1(2(4))(3)// 另一测试用例(左子树为空)TreeNode root2 = new TreeNode(1);root2.left = null;root2.right = new TreeNode(2);root2.right.left = new TreeNode(3);System.out.println(solution.tree2str(root2)); // 输出: 1()(2(3))}
}

十一,二叉树前序非递归遍历实现。

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;class TreeNode {int val;TreeNode left;TreeNode right;TreeNode(int x) {val = x;}
}public class PreorderTraversal {public List<Integer> preorderTraversal(TreeNode root) {List<Integer> result = new ArrayList<>();if (root == null) {return result;}// 用栈存储节点Stack<TreeNode> stack = new Stack<>();// 根节点先入栈stack.push(root);// 栈不为空时循环while (!stack.isEmpty()) {// 弹出栈顶节点(当前节点)并访问TreeNode 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;}// 测试代码public static void main(String[] args) {// 构建示例二叉树TreeNode root = new TreeNode(1);root.right = new TreeNode(2);root.right.left = new TreeNode(3);PreorderTraversal solution = new PreorderTraversal();List<Integer> result = solution.preorderTraversal(root);// 输出结果:[1, 2, 3]System.out.println(result);}
}


十二,二叉树中序非递归遍历实现。

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;class TreeNode {int val;TreeNode left;TreeNode right;TreeNode(int x) {val = x;}
}public class InorderTraversal {public List<Integer> inorderTraversal(TreeNode root) {List<Integer> result = new ArrayList<>();if (root == null) {return result;}Stack<TreeNode> stack = new Stack<>();TreeNode current = root; // 当前遍历的节点// 循环条件:栈不为空 或 当前节点不为空while (!stack.isEmpty() || current != null) {// 1. 将当前节点的所有左子节点入栈while (current != null) {stack.push(current);current = current.left; // 移动到左子节点}// 2. 弹出栈顶节点(左子树已遍历完),访问该节点current = stack.pop();result.add(current.val);// 3. 转向右子节点,重复上述过程current = current.right;}return result;}// 测试代码public static void main(String[] args) {// 构建示例二叉树TreeNode root = new TreeNode(1);root.right = new TreeNode(2);root.right.left = new TreeNode(3);InorderTraversal solution = new InorderTraversal();List<Integer> result = solution.inorderTraversal(root);// 输出结果:[1, 3, 2]System.out.println(result);}
}


十三,二叉树后序非递归遍历实现。

 import java.util.ArrayList;
import java.util.List;
import java.util.Stack;class TreeNode {int val;TreeNode left;TreeNode right;TreeNode(int x) {val = x;}
}public class PostorderTraversal {public List<Integer> postorderTraversal(TreeNode root) {List<Integer> result = new ArrayList<>();if (root == null) {return result;}Stack<TreeNode> stack = new Stack<>();TreeNode current = root;TreeNode lastVisited = null; // 记录上一次访问的节点while (!stack.isEmpty() || current != null) {// 1. 将当前节点的所有左子节点入栈while (current != null) {stack.push(current);current = current.left;}// 查看栈顶节点(不弹出)TreeNode peekNode = stack.peek();// 2. 若右子树为空 或 右子树已访问过,则访问当前节点if (peekNode.right == null || peekNode.right == lastVisited) {stack.pop(); // 弹出节点result.add(peekNode.val); // 访问节点lastVisited = peekNode; // 更新上一次访问的节点current = null; // 当前节点已处理,无需继续向左} else {// 3. 右子树未访问过,转向右子树current = peekNode.right;}}return result;}// 测试代码public static void main(String[] args) {// 构建示例二叉树TreeNode root = new TreeNode(1);root.right = new TreeNode(2);root.right.left = new TreeNode(3);PostorderTraversal solution = new PostorderTraversal();List<Integer> result = solution.postorderTraversal(root);// 输出结果:[3, 2, 1]System.out.println(result);}
}

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

相关文章:

  • uniapp本地打包详细教程
  • 做国外网站手机端网站的区别
  • 新网站开发费用参加sem培训
  • alexa怎么查询网站排名程序员都需要学什么
  • 长江工程建设局网站珠海做网站推广公司
  • 专业微网站建设百度mip wordpress
  • 做彩票网站程序违法吗在四川省住房和城乡建设厅网站上查
  • 中国建设银行下载官方网站开题报告网站开发方法
  • 成都营销型网站制作工厂型企业做网站
  • 免费不收费用网站wordpress开发团队
  • 滚动数组(空间优化)
  • 链表-哨兵节点链表【node5】
  • 中国国家住房和城乡建设部网站首页做网站的商家怎么后去流量费
  • 【Transformer入门到实战】神经网络基础知识和常见激活函数详解
  • 中国建设人才服务信息网是不是正规网站国家药品监督管理局
  • 中药饮片批发市场如何通过创新提升行业竞争力?
  • 宁波网站建设网页设计软件开发和网站开发难度
  • Java List 集合
  • 前缀和算法:高效解决区间和问题
  • 网站设计 价格湖南省建三公司官网
  • 阳江网络公司湖南seo推广方法
  • 丹东网站制作湖南人文科技学院简介
  • pandas转换为日期及期间切片
  • lol视频网站模板wordpress小说站模版
  • 免费申请账号网站卢松松网站
  • 站长统计幸福宝2022年排行榜网站优化过度被k
  • 看英语做游戏的网站长沙微网站
  • 整站优化 快速排名苏州园区人力资源中心
  • LeetCode算法日记 - Day 84: 乘积为正数的最长子数组长度
  • s001网站建设设计个人网站建设实训目的