1. 二叉树操作
1.1. 二叉树遍历:
问题描述:使用前序遍历、中序遍历、后序遍历和层次遍历输出二叉树的节点。
求解策略:根据定义,前三种遍历采用递归实现(也可以用非递归实现,见本文最后),而层次遍历采用队列(不是栈)来存储将要访问的元素。
1 | /* visit 函数 */ |
时间复杂度:这四种方法的时间和空间复杂度均为 O(n)。
1.2. 二叉树的高
问题描述:给一颗二叉树,求它的高度。
求解策略:利用递归。先取得左子树高度,然后获取右子树高度,最后把左右子树高度的最大者加上 1,即得到树的高度。
1 | /* 确定二叉树的高度 */ |
1.3. 二叉树遍历的非递归实现
问题描述:用非递归方法实现二叉树的前序遍历、中序遍历和后序遍历。
思路:
前序遍历(非递归):对任意结点 currNode
- 访问结点 currNode,并将其入栈;
- 判断结点 currNode 的左孩子是否为空,若不空,则将当前结点的左孩子置为当前结点;若为空,则取栈顶结点并进行出栈操作,并将栈顶结点的右孩子置为当前结点 currNode;
- 直到当前结点为空并且栈为空,遍历结束。
中序遍历(非递归):对任意结点 currNode
- 若其左孩子不为空,则将 currNode 入栈,并将 currNode 的左孩子结点置为 currNode,然后再对当前结点进行相同处理;
- 若其左孩子为空,则取栈顶元素进行出栈操作,访问该栈顶结点,然后将当前的结点 currNode 置为栈顶结点的右孩子;
- 直到 currNode 为空并且栈为空,遍历结束。
后序遍历(非递归,三种实现):
实现一:
要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点 currNode,先将其入栈。如果 currNode 不存在左孩子和右孩子,则可以直接访问它;或者 currNode 存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。若非上述两种情况,则将 currNode 的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。实现二:
该方法与方法一同理,实现方法不同。实现三:
用两个栈,先将根结点入第一个栈,然后每次从第一个栈中取出栈顶结点,将其如第二个栈,然后再将其左孩子和右孩子(如果有的话)依次入第一个栈,直到第一个栈为空。再将第二个栈的元素依次出栈即可。
代码实现:
1 |
|
代码输出:1
2
3
4
5
6
7
8
9
10preorder:
1 2 4 5 7 9 3 6 8
inorder:
4 2 7 9 5 1 3 8 6
postOrder:
4 9 7 5 2 8 6 3 1
postOrder2:
4 9 7 5 2 8 6 3 1
postOrder3:
4 9 7 5 2 8 6 3 1