当前位置:   article > 正文

算法体系-12 第 十二 二叉树的基本算法 下

算法体系-12 第 十二 二叉树的基本算法 下

一 实现二叉树的按层遍历

1.1 描述

1)其实就是宽度优先遍历,用队列

2)可以通过设置flag变量的方式,来发现某一层的结束(看题目)看下边的第四题解答

1.2 代码

  1. public class Code01_LevelTraversalBT {
  2. public static class Node {
  3. public int value;
  4. public Node left;
  5. public Node right;
  6. public Node(int v) {
  7. value = v;
  8. }
  9. }
  10. public static void level(Node head) {
  11. if (head == null) {
  12. return;
  13. }
  14. Queue<Node> queue = new LinkedList<>();
  15. queue.add(head);
  16. while (!queue.isEmpty()) {
  17. Node cur = queue.poll();
  18. System.out.println(cur.value);
  19. if (cur.left != null) {
  20. queue.add(cur.left);
  21. }
  22. if (cur.right != null) {
  23. queue.add(cur.right);
  24. }
  25. }
  26. }

二 实现二叉树的序列化和反序列化

2.1描述

1)先序方式序列化和反序列化

2)按层方式序列化和反序列化

将二叉树序力化为唯一的字符串叫序力化,字符串也能转出唯一的数二叉树叫反序力化

2.2 分析

2.3 前序列化代码

  1. public static class Node {
  2. public int value;
  3. public Node left;
  4. public Node right;
  5. public Node(int data) {
  6. this.value = data;
  7. }
  8. }
  9. public static Queue<String> preSerial(Node head) {
  10. Queue<String> ans = new LinkedList<>();
  11. pres(head, ans);
  12. return ans;
  13. }
  14. public static void pres(Node head, Queue<String> ans) {
  15. if (head == null) {
  16. ans.add(null);
  17. } else {
  18. ans.add(String.valueOf(head.value));
  19. pres(head.left, ans);
  20. pres(head.right, ans);
  21. }
  22. }

2.4 前序反序列化

  1. public static Node buildByPreQueue(Queue<String> prelist) {
  2. if (prelist == null || prelist.size() == 0) {
  3. return null;
  4. }
  5. return preb(prelist);
  6. }
  7. public static Node preb(Queue<String> prelist) {
  8. String value = prelist.poll();
  9. if (value == null) {
  10. return null;
  11. }
  12. Node head = new Node(Integer.valueOf(value));
  13. head.left = preb(prelist);
  14. head.right = preb(prelist);
  15. return head;
  16. }

2.5 中序列化代码

由上图可以知道,中序序例化是有歧义的,所以不存在中序的序列化

  1. public static Queue<String> inSerial(Node head) {
  2. Queue<String> ans = new LinkedList<>();
  3. ins(head, ans);
  4. return ans;
  5. }
  6. public static void ins(Node head, Queue<String> ans) {
  7. if (head == null) {
  8. ans.add(null);
  9. } else {
  10. ins(head.left, ans);
  11. ans.add(String.valueOf(head.value));
  12. ins(head.right, ans);
  13. }
  14. }

2.7 中序反列化 

2.8 后序列化代码

  1. public static Queue<String> posSerial(Node head) {
  2. Queue<String> ans = new LinkedList<>();
  3. poss(head, ans);
  4. return ans;
  5. }
  6. public static void poss(Node head, Queue<String> ans) {
  7. if (head == null) {
  8. ans.add(null);
  9. } else {
  10. poss(head.left, ans);
  11. poss(head.right, ans);
  12. ans.add(String.valueOf(head.value));
  13. }
  14. }

2.9后序反列化代码

  1. public static Node buildByPosQueue(Queue<String> poslist) {
  2. if (poslist == null || poslist.size() == 0) {
  3. return null;
  4. }
  5. // 左右中 -> stack(中右左) 默认是左右中,这种情况没法首先没法建立头节点,因此进行转化为头在前面的情况,把它放入stack(中右左),这是头就先出来,就可以新建head
  6. Stack<String> stack = new Stack<>();
  7. while (!poslist.isEmpty()) {
  8. stack.push(poslist.poll());
  9. }
  10. return posb(stack);
  11. }
  12. public static Node posb(Stack<String> posstack) {
  13. String value = posstack.pop();
  14. if (value == null) {
  15. return null;
  16. }
  17. Node head = new Node(Integer.valueOf(value));
  18. head.right = posb(posstack);
  19. head.left = posb(posstack);
  20. return head;
  21. }

3.0 按层序列化和反序列化

3.0.1分析

3.0.2 按层序列化 代码

  1. public static Queue<String> levelSerial(Node head) {
  2. Queue<String> ans = new LinkedList<>();
  3. if (head == null) {
  4. ans.add(null);
  5. } else {
  6. ans.add(String.valueOf(head.value));
  7. Queue<Node> queue = new LinkedList<Node>();
  8. queue.add(head);
  9. while (!queue.isEmpty()) {
  10. head = queue.poll(); // head 父 子
  11. if (head.left != null) {
  12. ans.add(String.valueOf(head.left.value));
  13. queue.add(head.left);
  14. } else {
  15. ans.add(null);
  16. }
  17. if (head.right != null) {
  18. ans.add(String.valueOf(head.right.value));
  19. queue.add(head.right);
  20. } else {
  21. ans.add(null);
  22. }
  23. }
  24. }
  25. return ans;
  26. }

3.0.3 按层反序列化 代码

  1. public static Node buildByLevelQueue(Queue<String> levelList) {
  2. if (levelList == null || levelList.size() == 0) {
  3. return null;
  4. }
  5. Node head = generateNode(levelList.poll());
  6. Queue<Node> queue = new LinkedList<Node>();
  7. if (head != null) {
  8. queue.add(head);
  9. }
  10. //因为要记录上一次的节点,这里借用队列来完成
  11. Node node = null;
  12. while (!queue.isEmpty()) {
  13. node = queue.poll();
  14. node.left = generateNode(levelList.poll());
  15. node.right = generateNode(levelList.poll());
  16. if (node.left != null) {
  17. queue.add(node.left);
  18. }
  19. if (node.right != null) {
  20. queue.add(node.right);
  21. }
  22. }
  23. return head;
  24. }
  25. public static Node generateNode(String val) {
  26. if (val == null) {
  27. return null;
  28. }
  29. return new Node(Integer.valueOf(val));
  30. }

三 Encode N-ary Tree to Binary Tree

3.1 描述

一颗多叉树,序历化为为二叉树,二叉树也能转为原来的多叉树;

3.2 分析

第一步 先将多叉树的每个节点的孩子放在对应节点左树的右边界上;

左树的节点为该节点的第一个树,反回来看某个节点是否有孩子看该节点左数是否有右边孩子

结构如下

3.3 代码

  1. package class11;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. // 本题测试链接:https://leetcode.com/problems/encode-n-ary-tree-to-binary-tree
  5. public class Code03_EncodeNaryTreeToBinaryTree {
  6. // 提交时不要提交这个类
  7. public static class Node {
  8. public int val;
  9. public List<Node> children;
  10. public Node() {
  11. }
  12. public Node(int _val) {
  13. val = _val;
  14. }
  15. public Node(int _val, List<Node> _children) {
  16. val = _val;
  17. children = _children;
  18. }
  19. };
  20. // 提交时不要提交这个类
  21. public static class TreeNode {
  22. int val;
  23. TreeNode left;
  24. TreeNode right;
  25. TreeNode(int x) {
  26. val = x;
  27. }
  28. }
  29. // 只提交这个类即可
  30. class Codec {
  31. // Encodes an n-ary tree to a binary tree.
  32. public TreeNode encode(Node root) {
  33. if (root == null) {
  34. return null;
  35. }
  36. TreeNode head = new TreeNode(root.val);
  37. head.left = en(root.children);
  38. return head;
  39. }
  40. private TreeNode en(List<Node> children) {
  41. TreeNode head = null;
  42. TreeNode cur = null;
  43. for (Node child : children) {
  44. TreeNode tNode = new TreeNode(child.val);
  45. if (head == null) {
  46. head = tNode;
  47. } else {
  48. cur.right = tNode;
  49. }
  50. cur = tNode;
  51. cur.left = en(child.children);
  52. }
  53. return head;
  54. }
  55. // Decodes your binary tree to an n-ary tree.
  56. public Node decode(TreeNode root) {
  57. if (root == null) {
  58. return null;
  59. }
  60. return new Node(root.val, de(root.left));
  61. }
  62. public List<Node> de(TreeNode root) {
  63. List<Node> children = new ArrayList<>();
  64. while (root != null) {
  65. Node cur = new Node(root.val, de(root.left));
  66. children.add(cur);
  67. root = root.right;
  68. }
  69. return children;
  70. }
  71. }
  72. }

四 求二叉树最宽的层有多少个节点

4.1 描述

打印二叉树每层的的节点树及最多的节点数;

4.2 分析

根据宽度优先遍历的基础上,要是能知道哪一层结束,那么就能算出每一层的节点数;

设计两个数,Node curEnd = head; // 当前层,最右节点是谁Node nextEnd = null; // 下一层,最右节点是谁

每次遍历当前节点时候,判断该节点是否和记录的curEnd节点相等,相等就是当前层结束了,把当前层的节点数更新到max中,

再将当前节点的每一个左右孩子更新到队列中的过程中,每一步都更新nextEnd的值为当前加队列的值,下一层遍历来的时候更新curEnd值为nextEnd

4.3 代码

  1. public static int maxWidthNoMap(Node head) {
  2. if (head == null) {
  3. return 0;
  4. }
  5. Queue<Node> queue = new LinkedList<>();
  6. queue.add(head);
  7. Node curEnd = head; // 当前层,最右节点是谁
  8. Node nextEnd = null; // 下一层的最右节点是谁。提前为下一层出来的end节点做准备
  9. int max = 0;
  10. int curLevelNodes = 0; // 当前层的节点数
  11. while (!queue.isEmpty()) {
  12. Node cur = queue.poll();
  13. if (cur.left != null) {
  14. queue.add(cur.left);
  15. nextEnd = cur.left;
  16. }
  17. if (cur.right != null) {
  18. queue.add(cur.right);
  19. nextEnd = cur.right;
  20. }
  21. curLevelNodes++;
  22. if (cur == curEnd) {
  23. max = Math.max(max, curLevelNodes);
  24. curLevelNodes = 0;
  25. curEnd = nextEnd;
  26. }
  27. }
  28. return max;
  29. }
  30. //使用额外HashMapd
  31. public static class Node {
  32. public int value;
  33. public Node left;
  34. public Node right;
  35. public Node(int data) {
  36. this.value = data;
  37. }
  38. }
  39. public static int maxWidthUseMap(Node head) {
  40. if (head == null) {
  41. return 0;
  42. }
  43. Queue<Node> queue = new LinkedList<>();
  44. queue.add(head);
  45. // key 在 哪一层,value
  46. HashMap<Node, Integer> levelMap = new HashMap<>();
  47. levelMap.put(head, 1);
  48. int curLevel = 1; // 当前你正在统计哪一层的宽度
  49. int curLevelNodes = 0; // 当前层curLevel层,宽度目前是多少
  50. int max = 0;
  51. while (!queue.isEmpty()) {
  52. Node cur = queue.poll();
  53. int curNodeLevel = levelMap.get(cur);
  54. if (cur.left != null) {
  55. levelMap.put(cur.left, curNodeLevel + 1);
  56. queue.add(cur.left);
  57. }
  58. if (cur.right != null) {
  59. levelMap.put(cur.right, curNodeLevel + 1);
  60. queue.add(cur.right);
  61. }
  62. if (curNodeLevel == curLevel) {
  63. curLevelNodes++;
  64. } else {
  65. max = Math.max(max, curLevelNodes);
  66. curLevel++;
  67. curLevelNodes = 1;
  68. }
  69. }
  70. max = Math.max(max, curLevelNodes);
  71. return max;
  72. }

五 二叉树中的某个节点,返回该节点的后继节点

5.1 描述

后继节点 :比如中序遍历,求该节点的4的后继节点,就是中序遍历遍历到该节点后的所有节点

二叉树结构如下定义:

Class Node {

V value;

Node left;

Node right;

Node parent;

}

给你二叉树中的某个节点,返回该节点的后继节点

5.2 分析 中序遍历

5.2.1 方案一 先通过parrent 找到的他的跟节点后,然后通root找到他的中序遍历,然后就可以找到该节点的后继节点

方案二

5.2.2 情况1一 如果该节点有右数,那么他的后继节点一定是他右树的最左侧节点

情况二 当该节点没有右树的时候,去找该节点是谁的节点左树的最右侧节点(中序遍历的本质理解)如果没有右子树,根据中序遍历的特点,下一个就应该是去找该节点是谁的节点左树的最右侧节点

情况二 讨论如下 找一个数的后继节点,一直往上找,通过找到该节点的最后一个父节点,该节点的右子树就是他的后继节点

如下,x是y左数的最右节点,所以打印完x就该打印y了 == 找的就是那个左树上的最右节点

5.3 代码

  1. public class Code06_SuccessorNode {
  2. public static class Node {
  3. public int value;
  4. public Node left;
  5. public Node right;
  6. public Node parent;
  7. public Node(int data) {
  8. this.value = data;
  9. }
  10. }
  11. public static Node getSuccessorNode(Node node) {
  12. if (node == null) {
  13. return node;
  14. }
  15. if (node.right != null) {
  16. return getLeftMost(node.right);
  17. } else { // 无右子树
  18. Node parent = node.parent;
  19. while (parent != null && parent.right == node) { // 当前节点是其父亲节点右孩子
  20. node = parent;
  21. parent = node.parent;
  22. }
  23. return parent;
  24. }
  25. }
  26. public static Node getLeftMost(Node node) {
  27. if (node == null) {
  28. return node;
  29. }
  30. while (node.left != null) {
  31. node = node.left;
  32. }
  33. return node;
  34. }

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

闽ICP备14008679号