当前位置:   article > 正文

【数据结构】二叉树重点知识和OJ题汇总(附有代码)_oj 1109. 扩展二叉树

oj 1109. 扩展二叉树

目录

思维导图:​

1.树的概念:

2.二叉树:

3.二叉树的遍历:

4.二叉树的模拟实现:

5.二叉树的OJ题:


思维导图

1.树的概念:

  1. 树是一种非线性的数据结构,由递归定义出来的。根节点R在上,其他节点在下;树形结构中子树不能有交集,否则不能称为树形结构。
  2. 树的几种重要概念,参照上图:
    1.节点的度:一个节点含有子树的个数,例如:c的度就是3
    2.树的度:一棵树中所有节点的度的最大值,例如:上图中树的度就是3
    3.叶子节点或终端节点:一个节点没有任何子树,例如:j、k、e、f、g、m、n、i
    4.双亲节点或父节点:一个节点含有子节点,例如:r是a、b、c的父节点
    5.孩子节点或子节点:例如:a、b、c是r的孩子节点
    6.根节点:一棵树中,没有双亲节点的节点,例如:r就是根节点
    7.节点的层次:从根开始算,r为第1层,a、b、c为第2层
    8.树的高度或深度:树中节点的最大层次,例如:上图中树的最大高度为4

2.二叉树:

  1. 二叉树是由1个根节点加上左子树和右子树组成的,每个根节点可以有2棵子树、1棵子树也可以没有子树。因此:二叉树不会存在度大于2的节点;二叉树的子树有左右之分,不可以颠倒;一颗二叉树的左子树和右子树也必须是二叉树。
  2. 有2种特殊的二叉树分别为满二叉树和完全二叉树。满二叉树是1棵二叉树上的每层节点数达到最大值,如果1棵二叉树的层数为n并且节点总数为 (2^n) - 1;则这棵树就是满二叉树。
  3. 二叉树的性质:
    1.规定根节点的层数为1,则1棵非空二叉树的第i层上最多有2^(i-1)个节点
    2.规定根节点的二叉树高度为1,则高度为k的二叉树最大节点数是2^k - 1
    3.度为0的节点个数比度为2的个数多1个
    4.有n个节点的完全二叉树的深度为log以2为底的(n+1)向上取整
    
  4. 二叉树的存储是通过一个一个的节点引用起来的,常用的表示方式有孩子表示法和孩子双亲表示法。二叉树的存储分为顺序存储和类似于链表的链式存储,注意类似于链表不是链表

 

3.二叉树的遍历

  1. 二叉树的遍历是二叉树最重要的基本功能。
  2. 前序遍历:先访问根节点—>左子树—>右子树
    参照上图前序遍历:r a d e c g i
    
  3. 中序遍历:先访问左子树—>根节点—>右子树
    参照上图中序遍历:d a e r g c i
    
  4. 后序遍历:先访问左子树—>右子树—>根节点
    参照上图后序遍历:d e a g i c r
  5. 层序遍历:从左到右遍历每一层
    参照上图层序遍历:r a c d e g i
  6. 根据前序遍历和后序遍历不能创建出一个二叉树,前序和后序只能确定根
  7. 前、中、后、层+序遍历的代码实现:
  1. public class BinaryTree {
  2. class TreeNode{
  3. //孩子表示法
  4. public char val;
  5. public TreeNode left;
  6. public TreeNode right;
  7. public TreeNode(char val){
  8. this.val = val;
  9. }
  10. }
  11. public TreeNode root;
  12. //前序遍历1
  13. public void preOrder1(TreeNode root){
  14. if(root == null) return;
  15. System.out.print(root.val+" ");
  16. preOrder1(root.left);
  17. preOrder1(root.right);
  18. }
  19. //前序遍历2:有返回值类型,遍历思路
  20. class Solution{
  21. //list必须定义在外面,否则每次递归都会创建1个list
  22. List<Character> list = new ArrayList<>();
  23. public List<Character> preOrder2(TreeNode root){
  24. if(root == null) return list;
  25. list.add(root.val);
  26. preOrder2(root.left);
  27. preOrder2(root.right);
  28. return list;
  29. }
  30. }
  31. //前序遍历3:有返回值,子问题思路
  32. public List<Character> preOrder3(TreeNode root){
  33. List<Character> list = new ArrayList<>();
  34. if(root == null) return list;
  35. list.add(root.val);
  36. List<Character> leftTree = preOrder3(root.left);
  37. list.addAll(leftTree);
  38. List<Character> rightTree = preOrder3(root.right);
  39. list.addAll(rightTree);
  40. return list;
  41. }
  42. //中序遍历1
  43. public void inOrder(TreeNode root){
  44. if(root == null) return;
  45. inOrder(root.left);
  46. System.out.print(root.val+" ");
  47. inOrder(root.right);
  48. }
  49. //中序遍历2:有返回值,子问题思路
  50. public List<Character> inOrder2(TreeNode root){
  51. List<Character> list = new ArrayList<>();
  52. if(root == null) return list;
  53. List<Character> leftTree = inOrder2(root.left);
  54. list.addAll(leftTree);
  55. list.add(root.val);
  56. List<Character> rightTree = inOrder2(root.right);
  57. list.addAll(rightTree);
  58. return list;
  59. }
  60. //后序遍历1
  61. public void postOrder(TreeNode root){
  62. if(root == null) return;
  63. postOrder(root.left);
  64. postOrder(root.right);
  65. System.out.print(root.val+" ");
  66. }
  67. //后序遍历2:有返回值,子问题思路
  68. public List<Character> postOrder2(TreeNode root){
  69. List<Character> list = new ArrayList<>();
  70. if(root == null) return list;
  71. List<Character> leftTree = postOrder(root.left);
  72. list.addAll(leftTree);
  73. List<Character> rightTree = postOrder2(root.right);
  74. list.addAll(rightTree);
  75. list.add(root.val);
  76. return list;
  77. }
  78. //层序遍历1:使用到了队列
  79. public void levelOrder(TreeNode root){
  80. if(root == null) return;
  81. Queue<TreeNode> queue = new LinkedList<>();
  82. queue.offer(root);
  83. while(!queue.isEmpty()){
  84. TreeNode cur = queue.poll();
  85. System.out.print(cur+" ");
  86. if(cur.left != null){
  87. queue.offer(cur.left);
  88. }
  89. if(cur.right != null){
  90. queue.offer(cur.right);
  91. }
  92. }
  93. }
  94. }

 

4.二叉树的模拟实现:

获取树中节点得个数

 获取叶子节点的个数

 获取第k层节点的个数

 获取二叉树的高度

 检测值value是否存在

 代码实现如下:

  1. public class BinaryTree {
  2. class TreeNode{
  3. //孩子表示法
  4. public char val;
  5. public TreeNode left;
  6. public TreeNode right;
  7. public TreeNode(char val){
  8. this.val = val;
  9. }
  10. }
  11. public TreeNode root;
  12. //获取树中节点的个数1:子问题思路
  13. public int size(TreeNode root){
  14. if(root == null) return 0;
  15. return size(root.left)+size(root.right)+1;
  16. }
  17. //获取树中节点的个数2:遍历思路
  18. public static int nodeSize;
  19. public void size2(TreeNode root){
  20. if(root == null) return;
  21. nodeSize++;
  22. size2(root.left);
  23. size2(root.right);
  24. }
  25. //获取叶子节点的个数1:子问题思路
  26. public int getLeafNodeCount(TreeNode root){
  27. if(root == null) return 0;
  28. if(root.left == null && root.right==null){
  29. return 1;
  30. }
  31. return getLeafNodeCount(root.left)+
  32. getLeafNodeCount(root.right);
  33. }
  34. //获取叶子节点的个数2:遍历思路
  35. public static int leafSize;
  36. public void getLeafNodeCount2(TreeNode root){
  37. if(root == null) return;
  38. if(root.left == null && root.right == null){
  39. leafSize++;
  40. }
  41. getLeafNodeCount2(root.left);
  42. getLeafNodeCount2(root.right);
  43. }
  44. //获取第k层节点的个数:子问题思路
  45. public int getKLevelNodeCount(TreeNode root,int k){
  46. if(root == null) return 0;
  47. if(k == 1) return 1;
  48. //对k操作不会影响右树
  49. return getKLevelNodeCount(root.left,k-1)
  50. +getKLevelNodeCount(root.right,k-1);
  51. }
  52. //获取二叉树的高度
  53. public int getHeight(TreeNode root){
  54. if(root == null) return 0;
  55. int leftHeight = getHeight(root.left);
  56. int rightHeight = getHeight(root.right);
  57. return (leftHeight > rightHeight?
  58. leftHeight+1 : rightHeight+1);
  59. }
  60. //检测value是否存在
  61. public TreeNode find(TreeNode root,int value){
  62. if(root == null) return null;
  63. if(root.val == value){
  64. return root;
  65. }
  66. TreeNode ret1 = find(root.left,value);
  67. if(ret1 != null) return ret1;
  68. TreeNode ret2 = find(root.right,value);
  69. if(ret2 != null) return ret2;
  70. return null;
  71. }
  72. //判断一棵树是不是完全二叉树
  73. public boolean isCompleteTree(TreeNode root){
  74. if(root == null) return true;
  75. Queue<TreeNode> queue = new LinkedList<>();
  76. queue.offer(root);
  77. while(!queue.isEmpty()){
  78. TreeNode cur = queue.poll();
  79. System.out.println(cur+" ");
  80. if(cur != null){
  81. queue.offer(cur.left);
  82. queue.offer(cur.right);
  83. }else{
  84. break;
  85. }
  86. }
  87. while(!queue.isEmpty()){
  88. TreeNode cur = queue.peek();
  89. if(cur != null){
  90. return false;
  91. }else{
  92. queue.poll();
  93. }
  94. }
  95. return true;
  96. }
  97. }

5.二叉树的OJ题:

1.检查俩颗二叉树是否完全相同,时间复杂度为O(min(m,n))

  1. //检查俩颗树是否完全相同
  2. public boolean isSameTree(TreeNode p,TreeNode q){
  3. if(p == null &&q != null || q == null && p != null) return false;
  4. if(p == null && q == null) return true;
  5. if(p.val == q.val) return true;
  6. return isSameTree(p.left,q.left) &&
  7. isSameTree(p.right,q.right);
  8. }

2.判断一棵树是不是另外一棵树的子树,时间复杂度为O(m*n)

  1. //判断一棵树是不是另外一棵树的子树
  2. public boolean isSubTree(TreeNode root,TreeNode subRoot){
  3. if(root == null || subRoot == null) return false;
  4. if(isSameTree(root,subRoot)) return true;
  5. if(isSameTree(root.left,subRoot)) return true;
  6. if(isSameTree(root.right,subRoot)) return true;
  7. return false;
  8. }

3.二叉树的最大深度

  1. //得到一棵树的高度
  2. private int getHeight(TreeNode root) {
  3. if(root == null) return 0;
  4. int leftTree = getHeight(root.left);
  5. int rightTree = getHeight(root.right);
  6. return leftTree > rightTree?
  7. leftTree+1 : rightTree+1;
  8. }

4.判断一棵树是不是平衡二叉树

  1. //得到一棵树的高度
  2. private int getHeight(TreeNode root) {
  3. if(root == null) return 0;
  4. int leftTree = getHeight(root.left);
  5. int rightTree = getHeight(root.right);
  6. return leftTree > rightTree?
  7. leftTree+1 : rightTree+1;
  8. }
  9. //1.判断一棵树是否是平衡二叉树,时间复杂度为O(n^2)
  10. public boolean isBalanced(TreeNode root){
  11. if(root == null){
  12. return true;
  13. }
  14. int leftTree = getHeight(root.left);
  15. int rightTree = getHeight(root.right);
  16. return Math.abs(leftTree-rightTree)<=1
  17. && isBalanced(root.left)
  18. && isBalanced(root.right);
  19. }
  20. //2.判断一棵树是否是平衡二叉树,时间复杂度为O(n)
  21. public boolean isBalanced2(TreeNode root){
  22. if(root == null) return true;
  23. return maxDepth(root)>=0;
  24. }
  25. private int maxDepth(TreeNode root) {
  26. if(root == null) return 0;
  27. int leftTree = maxDepth(root.left);
  28. int rightTree = maxDepth(root.right);
  29. if(leftTree >= 0 && rightTree >= 0 && Math.abs(leftTree-rightTree) <= 1){
  30. return Math.max(leftTree,rightTree)+1;
  31. }else{
  32. return -1;
  33. }
  34. }

5.构建一颗二叉树

  1. //构建一颗二叉树
  2. public static int i;
  3. public TreeNode createTree(String s){
  4. TreeNode root = null;
  5. if(s.charAt(i) != '#'){
  6. root = new TreeNode(s.charAt(i));
  7. i++;
  8. root.left = createTree(s);
  9. root.right = createTree(s);
  10. }else{
  11. i++;
  12. }
  13. return root;
  14. }

6.二叉树的分层遍历

  1. //二叉树的分层遍历
  2. public List<List<Character>> levelOrder(TreeNode root){
  3. List<List<Character>> ret = new ArrayList<>();
  4. if(root == null) return ret;
  5. Queue<TreeNode> queue = new LinkedList<>();
  6. queue.offer(root);
  7. while(!queue.isEmpty()){
  8. int size = queue.size();
  9. List<Character> row = new ArrayList<>();
  10. while(size > 0){
  11. TreeNode cur = queue.poll();
  12. size--;
  13. row.add(cur.val);
  14. if(cur.left != null){
  15. queue.offer(cur.left);
  16. }
  17. if(cur.right != null){
  18. queue.offer(cur.right);
  19. }
  20. }
  21. ret.add(row);
  22. }
  23. return ret;
  24. }

7.找到俩个二叉树的公共祖先

  1. //找俩个节点的公共祖先,方法1
  2. public TreeNode lowestAncestor(TreeNode root,TreeNode p,TreeNode q){
  3. if(root == null) return null;
  4. if(root == p || root == q) return root;
  5. TreeNode retleft = lowestAncestor(root.left,p,q);
  6. TreeNode retright = lowestAncestor(root.right,p,q);
  7. if(retleft != null && retright != null){
  8. return root;
  9. } else if (retleft != null) {
  10. return retleft;
  11. }else{
  12. return retright;
  13. }
  14. }
  15. //找俩个节点的公共祖先,方法2:找到根节点到指定节点之间的所有节点,存到stack中
  16. private boolean getPath(TreeNode root, TreeNode node, Stack<TreeNode> stack){
  17. if(root == null || node == null) return false;
  18. stack.push(root);
  19. if(root == node) return true;
  20. boolean ret1 = getPath(root.left,node,stack);
  21. if(ret1 == true) return true;
  22. boolean ret2 = getPath(root.right,node,stack);
  23. if(ret2 == true) return true;
  24. stack.pop();
  25. return false;
  26. }
  27. public TreeNode lowestAncestor2(TreeNode root,TreeNode p,TreeNode q){
  28. if(root == null || p == null || q == null) return null;
  29. Stack<TreeNode> stack1 = new Stack<>();
  30. getPath(root,p,stack1);
  31. Stack<TreeNode> stack2 = new Stack<>();
  32. getPath(root,q,stack2);
  33. int size1 = stack1.size();
  34. int size2 = stack2.size();
  35. if(size1 > size2){
  36. int tmp = size1 - size2;
  37. while(tmp != 0){
  38. stack1.pop();
  39. tmp--;
  40. }
  41. }else{
  42. int tmp = size2 - size1;
  43. while(tmp != 0){
  44. stack2.pop();
  45. tmp--;
  46. }
  47. while(! stack1.empty() && !stack2.empty()){
  48. if(stack1.peek() == stack2.peek()){
  49. return stack1.peek();
  50. }else{
  51. stack1.pop();
  52. stack2.pop();
  53. }
  54. }
  55. return null;
  56. }

8.将二叉搜索树转换成排序双向链表

  1. //二叉搜索树转换成排序双向链表
  2. public TreeNode prev = null;
  3. private void ConvertChild(TreeNode root){
  4. if(root == null) return ;
  5. ConvertChild(root.left);
  6. root.left = prev;
  7. if(prev != null){
  8. prev.right = root;
  9. }
  10. prev = root;
  11. ConvertChild(root.right);
  12. }
  13. public TreeNode Convert(TreeNode pRootOfTree){
  14. if(pRootOfTree == null) return null;
  15. ConvertChild(pRootOfTree);
  16. TreeNode head = pRootOfTree;
  17. while(head.left != null){
  18. head = head.left;
  19. }
  20. return head;
  21. }

9.根据前序和后序遍历构造二叉树

  1. //根据前序和中序遍历构造二叉树
  2. public int preindex = 0;
  3. private TreeNode buildTreeChild(int[] preorder,int[] inorder,int inbegin,int inend){
  4. //没有了左树或没有右树
  5. if(inbegin > inend) return null;
  6. TreeNode root = new TreeNode(preorder[preindex]);
  7. //找到当前根节点在中序遍历中的位置
  8. int rootIndex = findInorderIndex(inorder,preorder[preindex],inbegin,inend);
  9. preindex++;
  10. root.left = buildTreeChild(preorder,inorder,inbegin,rootIndex-1);
  11. root.right = buildTreeChild(preorder,inorder,rootIndex+1,inend);
  12. return root;
  13. }
  14. private int findInorderIndex(int[] inorder,int val,int inbegin,int inend){
  15. for (int i = inbegin; i <= inend; i++) {
  16. if (inorder[i] == val){
  17. return i;
  18. }
  19. }
  20. return -1;
  21. }
  22. public TreeNode buildTree(int[] preorder,int[] inorder){
  23. return buildTreeChild(preorder,inorder,0,inorder.length-1);
  24. }

10.根据中序和后序遍历构造二叉树

  1. //根据中序和后序遍历构造二叉树
  2. public int postindex = 0;
  3. private TreeNode buildTreeChild(int[] postorder,int[] inorder,int inbegin,int inend){
  4. //没有了左树或没有右树
  5. if(inbegin > inend) return null;
  6. TreeNode root = new TreeNode(postorder[postindex]);
  7. //找到当前根节点在中序遍历中的位置
  8. int rootIndex = findInorderIndex(inorder,postorder[postindex],inbegin,inend);
  9. postindex--;
  10. root.right = buildTreeChild(postorder,inorder,rootIndex+1,inend);
  11. root.left = buildTreeChild(postorder,inorder,inbegin,rootIndex-1);
  12. return root;
  13. }
  14. private int findInorderIndex(int[] inorder,int val,int inbegin,int inend){
  15. for (int i = inbegin; i <= inend; i++) {
  16. if (inorder[i] == val){
  17. return i;
  18. }
  19. }
  20. return -1;
  21. }
  22. public TreeNode buildTree(int[] postorder,int[] inorder){
  23. postindex = postorder.length-1;
  24. return buildTreeChild(postorder,inorder,0,inorder.length-1);
  25. }

11.二叉树创建字符串

  1. //二叉树创建字符串
  2. public String tree2str(TreeNode root) {
  3. StringBuilder sb = new StringBuilder();
  4. tree2strChild(root,sb);
  5. return sb.toString();
  6. }
  7. private void tree2strChild(TreeNode t,StringBuilder sb) {
  8. if(t == null) return ;
  9. sb.append(t.val);
  10. if(t.left != null) {
  11. sb.append("(");
  12. tree2strChild(t.left,sb);
  13. sb.append(")");
  14. }else {
  15. if(t.right == null) {
  16. return;
  17. }else{
  18. sb.append("()");
  19. }
  20. }
  21. if(t.right == null) {
  22. return;
  23. }else{
  24. sb.append("(");
  25. tree2strChild(t.right,sb);
  26. sb.append(")");
  27. }
  28. }

12.非递归实现前序遍历

  1. //非递归实现前序遍历
  2. public void preorderTraversalNor(TreeNode root) {
  3. Stack<TreeNode> stack = new Stack<>();
  4. TreeNode cur = root;
  5. while (cur != null || !stack.empty()) {
  6. while (cur != null) {
  7. stack.push(cur);
  8. System.out.print(cur.val + " ");
  9. cur = cur.left;
  10. }
  11. TreeNode top = stack.pop();
  12. cur = top.right;
  13. }
  14. }

13.非递归实现中序遍历

  1. //非递归实现中序遍历
  2. public void inorderTraversal(TreeNode root) {
  3. Stack<TreeNode> stack = new Stack<>();
  4. TreeNode cur = root;
  5. while (cur != null || !stack.empty()) {
  6. while (cur != null) {
  7. stack.push(cur);
  8. cur = cur.left;
  9. }
  10. TreeNode top = stack.pop();
  11. System.out.print(top.val + " ");
  12. cur = top.right;
  13. }
  14. }

14.非递归实现后序遍历

  1. //非递归实现后序遍历
  2. public void postorderTraversal(TreeNode root) {
  3. Stack<TreeNode> stack = new Stack<>();
  4. TreeNode prev = null;
  5. TreeNode cur = root;
  6. while (cur != null || !stack.empty()) {
  7. while (cur != null) {
  8. stack.push(cur);
  9. cur = cur.left;
  10. }
  11. TreeNode top = stack.peek();
  12. //top.right 如果已经被访问了 也要弹出top所指向的节点
  13. if (top.right == null || top.right == prev) {
  14. stack.pop();
  15. System.out.print(top.val + " ");
  16. prev = top;
  17. } else {
  18. cur = top.right;
  19. }
  20. }
  21. }

如果对您有帮助的话,

不要忘记点赞+关注哦,蟹蟹

如果对您有帮助的话,

不要忘记点赞+关注哦,蟹蟹

如果对您有帮助的话,

不要忘记点赞+关注哦,蟹蟹

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/寸_铁/article/detail/948465
推荐阅读
相关标签
  

闽ICP备14008679号