二叉树【基础算法题】

题目一

 思路

1)递归

忽略打印,实际上递归节点到达每个节点的顺序如图。打印的时机放到第一行就是先序遍历,打印的时机放到第二行就是中序遍历,打印的时机放到第三行就是后序遍历。

先序遍历:根节点→左子树→右子树。按照忽略打印实际递归顺序每个数第一次出现的顺序。1 2 4 5 3 6 7

中序遍历:左子树→根节点→右子树。按照忽略打印实际递归顺序每个数第二次出现的顺序。4 2 5 1 6 3  7

后续遍历:左子树→右子树→根节点。按照忽略打印实际递归顺序每个数第三次出现的顺序。4 5 2 6 7 3 1

2)非递归

自己准备一个栈。

先序遍历

1 2 4 5 3 6 7  中左右

如果头结点为空不打印,如果不为空压入栈中,进入while循环。

如果栈不为空,将栈中栈顶节点出栈并打印。如果当前节点右孩子不为空则将其压入栈中,如果当前节点左孩子不为空则将其压入栈中。

···以此类推,不断循环这个过程,直到所有节点都遍历完。

步骤:

1 压栈

1 出栈 打印

3 压栈 2压栈

2 出栈 打印

5 压栈 4 压栈

4 出栈 打印

5 出栈 打印

3 出栈 打印

7 压栈 6 压栈

6 出栈 打印

7 出栈 打印

中序遍历

4 2 5 1 6 3  7 左中右

如果头结点为空什么都不做,如果不为空,准备好一个栈。

如果栈不为空,或者头结点不为空,进入while循环。

如果当前节点不为null,会把自己压栈,当前节点向左移动。

如果当前节点为null,栈顶元素出栈并打印,当前节点向右移动。

···以此类推,不断循环这个过程,直到所有节点都遍历完。

步骤:

1 压栈 2压栈 4压栈

当前节点到了4的左孩子 为null

4 出栈 打印

当前节点到了4的右孩子 为null

2 出栈 打印

当前节点到了2的右孩子 不为null

5 压栈

当前节点到了5的左孩子 为null

5 出栈 打印

当前节点到了5的右孩子 为null

1 出栈 打印

当前节点到了1的右孩子 不为null

3 压栈

当前节点到了3的左孩子 不为null

6 压栈

当前节点到了6的左孩子 为null

6 出栈 打印

当前节点到了6的右孩子 为null

3 出栈 打印

当前节点到了3的右孩子 不为null

7 压栈

当前节点到了7的左孩子 为null

7 出栈 打印

当前节点到了7的右孩子 为null

此时栈空,退出循环,遍历结束。

后序遍历

4 5 2 6 7 3 1 左右中

方法一:准备两个栈,根据先序遍历的中左右,调整为中右左的顺序,将这个顺序压入另一个栈中,依次出栈的顺序就是左右中了。

方法二:使用一个栈。

代码实现

  1 package class_04;
  2 
  3 import java.util.Stack;
  4 
  5 public class Code_01_PreInPosTraversal {
  6 
  7     public static class Node {
  8         public int value;
  9         public Node left;
 10         public Node right;
 11 
 12         public Node(int data) {
 13             this.value = data;
 14         }
 15     }
 16 
 17     public static void preOrderRecur(Node head) {//递归先序
 18         if (head == null) {
 19             return;
 20         }
 21         System.out.print(head.value + " ");
 22         preOrderRecur(head.left);
 23         preOrderRecur(head.right);
 24     }
 25 
 26     public static void inOrderRecur(Node head) {//递归中序
 27         if (head == null) {
 28             return;
 29         }
 30         inOrderRecur(head.left);
 31         System.out.print(head.value + " ");
 32         inOrderRecur(head.right);
 33     }
 34 
 35     public static void posOrderRecur(Node head) {//递归后序
 36         if (head == null) {
 37             return;
 38         }
 39         posOrderRecur(head.left);
 40         posOrderRecur(head.right);
 41         System.out.print(head.value + " ");
 42     }
 43 
 44     public static void preOrderUnRecur(Node head) {//非递归先序
 45         System.out.print("pre-order: ");
 46         if (head != null) {
 47             Stack<Node> stack = new Stack<Node>();
 48             stack.add(head);
 49             while (!stack.isEmpty()) {
 50                 head = stack.pop();
 51                 System.out.print(head.value + " ");
 52                 if (head.right != null) {
 53                     stack.push(head.right);
 54                 }
 55                 if (head.left != null) {
 56                     stack.push(head.left);
 57                 }
 58             }
 59         }
 60         System.out.println();
 61     }
 62 
 63     public static void inOrderUnRecur(Node head) {//非递归中序
 64         System.out.print("in-order: ");
 65         if (head != null) {
 66             Stack<Node> stack = new Stack<Node>();
 67             while (!stack.isEmpty() || head != null) {
 68                 if (head != null) {
 69                     stack.push(head);
 70                     head = head.left;
 71                 } else {
 72                     head = stack.pop();
 73                     System.out.print(head.value + " ");
 74                     head = head.right;
 75                 }
 76             }
 77         }
 78         System.out.println();
 79     }
 80 
 81     public static void posOrderUnRecur1(Node head) {//非递归后序
 82         System.out.print("pos-order: ");
 83         if (head != null) {
 84             Stack<Node> s1 = new Stack<Node>();
 85             Stack<Node> s2 = new Stack<Node>();
 86             s1.push(head);
 87             while (!s1.isEmpty()) {
 88                 head = s1.pop();
 89                 s2.push(head);
 90                 if (head.left != null) {
 91                     s1.push(head.left);
 92                 }
 93                 if (head.right != null) {
 94                     s1.push(head.right);
 95                 }
 96             }
 97             while (!s2.isEmpty()) {
 98                 System.out.print(s2.pop().value + " ");
 99             }
100         }
101         System.out.println();
102     }
103 
104     public static void posOrderUnRecur2(Node h) {
105         System.out.print("pos-order: ");
106         if (h != null) {
107             Stack<Node> stack = new Stack<Node>();
108             stack.push(h);
109             Node c = null;
110             while (!stack.isEmpty()) {
111                 c = stack.peek();
112                 if (c.left != null && h != c.left && h != c.right) {
113                     stack.push(c.left);
114                 } else if (c.right != null && h != c.right) {
115                     stack.push(c.right);
116                 } else {
117                     System.out.print(stack.pop().value + " ");
118                     h = c;
119                 }
120             }
121         }
122         System.out.println();
123     }
124 
125     public static void main(String[] args) {
126         Node head = new Node(5);
127         head.left = new Node(3);
128         head.right = new Node(8);
129         head.left.left = new Node(2);
130         head.left.right = new Node(4);
131         head.left.left.left = new Node(1);
132         head.right.left = new Node(7);
133         head.right.left.left = new Node(6);
134         head.right.right = new Node(10);
135         head.right.right.left = new Node(9);
136         head.right.right.right = new Node(11);
137 
138         // recursive
139         System.out.println("==============recursive==============");
140         System.out.print("pre-order: ");
141         preOrderRecur(head);
142         System.out.println();
143         System.out.print("in-order: ");
144         inOrderRecur(head);
145         System.out.println();
146         System.out.print("pos-order: ");
147         posOrderRecur(head);
148         System.out.println();
149 
150         // unrecursive
151         System.out.println("============unrecursive=============");
152         preOrderUnRecur(head);
153         inOrderUnRecur(head);
154         posOrderUnRecur1(head);
155         posOrderUnRecur2(head);
156 
157     }
158 
159 }

题目二

 思路

H*H是头结点*。

v*v是代表*的父节点是左下方离*最近的。

^*^是代表*的父节点是左上方离*最近的。

   

代码实现

直观打印二叉树

题目三

思路

每个节点都能通过它的parent指针找到它的父节点;头结点的父指针指向自己或null,大多情况都设置为null。

 在中序遍历的序列中,一个节点的下一个节点(后继节点)是它的父节点。

 

 例:如果只给了其中一个节点,可以通过它的parent指针,一路找到头结点,再从头结点进行中序遍历,这样就能找到所有节点的父节点,但是这样要遍历整颗树,复杂度较高。

怎么能不遍历整颗树也能找到某节点的父节点呢?

在中序遍历序列中,

①一个节点,只要其有右子树,那它的后继节点一定是它的整颗右子树中最左的那个节点。

②一个节点x,若其没有右子树,要考察到底那个节点作为其整颗左子树的最后一个节点。如果没有就是不存在。例如节点7没有后继节点。

(通过x的parent指针往上找,如果x是它父节点的右孩子,继续往上找,当前节点变为x的父节点,直到当前节点是当前节点的父节点的左孩子停止,当前节点的父节点就是x的后继节点,如果某一步parent是空,则表示x没有后继节点。)

         11的后继是1

举一反三:怎么找一个节点的前驱节点?

①一个节点,只要其有左子树,那它的前驱节点一定是它的整颗左子树中最右的那个节点。

②一个节点x,若其没有左子树,通过x的parent指针往上找,如果x是它父节点的左孩子,继续往上找,当前节点变为x的父节点,直到当前节点是当前节点的父节点的右孩子停止,当前节点的父节点就是x的前驱节点,如果某一步parent是空,则表示x没有前驱节点。

代码实现

查找二叉树中某个节点的后继节点

题目四

 思路

在内存里可以串起一棵树,但关机的时候,内存里的东西就销毁了,怎么能把它变成文件的形式记录下来,以便能把树重建?

把内存中的树记录下来的过程就叫序列化,重建树(还原内存中树结构)的过程就叫反序列化

【方法一】

先序的方式序列化

按照先序遍历得到的顺序来组成一个字符串,存储起来,每个节点后有一个下划线(用于隔开各个节点),当前节点为null时,用#代替节点。

加上空是为了区分结构(当节点的值相等时,会存在它的先序中序后序是一样的的情况)。

先序的方式反序列化

怎么序列化就怎么反序列化。

第一个数是根节点,依次按先序顺序(中左右)来建立树,当前节点x为null时,不再继续往下,当前节点x回到它的父节点y,再走到y的右孩子,当遍历过右孩子后,继续往上走,以此类推,直到所有节点都建立完毕。

中序和后序遍历的序列化和反序列化类似。

【方法二】

按层序列化

代码实现

序列化代码

题目五

 代码实现

 折纸代码

题目六

 思路

平衡二叉树:对于一颗二叉树中的任何节点,它的左右子树的高度差不超过1。满二叉树一定时平衡二叉树,但平衡二叉树不一定是满二叉树。平衡性主要是用来解决效率问题的。

如果树中以每一个节点作为头结点的树都是平衡树,则整棵树是平衡的。

1)左树是否平衡,左树不平衡直接返回false。

2)左树平衡了,右树是否平衡?右树不平衡返回false。

3)左树和右树都平衡,左树的高度是几?右树的高度是几?

4)判断左树和右树的高度差,即可判断出整棵树是否平衡。

由以上分析可知,我们的递归函数需要返回两个信息,当前树是否是平衡的,以及这棵树的高度。

关键词:树形BP

代码实现

 1 package class_04;
 2 
 3 public class Code_06_IsBalancedTree {
 4 
 5     public static class Node {
 6         public int value;
 7         public Node left;
 8         public Node right;
 9 
10         public Node(int data) {
11             this.value = data;
12         }
13     }
14 
15     public static boolean isBalance(Node head) {
16         boolean[] res = new boolean[1];
17         res[0] = true;
18         getHeight(head, 1, res);
19         return res[0];
20     }
21 
22     public static int getHeight(Node head, int level, boolean[] res) {
23         if (head == null) {
24             return level;
25         }
26         int lH = getHeight(head.left, level + 1, res);
27         if (!res[0]) {
28             return level;
29         }
30         int rH = getHeight(head.right, level + 1, res);
31         if (!res[0]) {
32             return level;
33         }
34         if (Math.abs(lH - rH) > 1) {
35             res[0] = false;
36         }
37         return Math.max(lH, rH);
38     }
39 
40     public static void main(String[] args) {
41         Node head = new Node(1);
42         head.left = new Node(2);
43         head.right = new Node(3);
44         head.left.left = new Node(4);
45         head.left.right = new Node(5);
46         head.right.left = new Node(6);
47         head.right.right = new Node(7);
48 
49         System.out.println(isBalance(head));
50 
51     }
52 }

题目七

 思路

搜索二叉树:对于树中任意一个节点x为头的子树,左子树都比x小,右子树都比x大。

二叉树的中序遍历的节点是依次升序的就是搜索二叉树!

完全二叉树:对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。

判断逻辑:二叉树按层遍历。

1)一个结点有右孩子,没有左孩子,一定不是完全二叉树。返回false。

2)一个结点只有左孩子没有右孩子 或者 左右孩子都没有,后面遇到的所有结点都必须是叶节点,否则不是完全二叉树,返回false。 

代码实现

 判断搜索二叉树和完全二叉树

题目八

 思路

二叉树实现的堆,没有空间浪费,没有扩容代价。这两个方面比使用数组实现堆更好。

因为时间复杂度的要求,不能用遍历的方式获取。

满二叉树的高度为L ,它的节点个数是2^L -1。

完全二叉树:

①遍历整棵树的左边界,看看左边界最后一个结点到了哪一层。代价是O(logn)。

②遍历头结点x的右子树的左边界,看看右子树的左边界到没到最后一层。

  如果到了最后一层,说明整棵树的左子树的满的,能够得到整棵树左子树的高度H左,进而得到左子树的节点数,2^H左 -1,加上当前节点,一共是2^H左 个节点。整棵树的右子树也是一颗完全二叉树,递归求出右树的节点数。

  如果没到最后一层,说明整棵树的右子树是满的,能够得到整棵树右子树的高度H右,进而得到右子树的节点数,2^H右 -1,加上当前节点,一共是2^H右 个节点。整棵树的左子树也是一颗完全二叉树,递归求出左子树的节点数。

复杂度:

每一层只遍历一个节点 O(logn),遍历每一个子树的边界O(logn)。

总复杂度 O(logn)*O(logn)。

代码实现

完全二叉树节点的个数

原文地址:https://www.cnblogs.com/superjishere/p/12298559.html