您的位置:首页 > 其它

leetcode(145):Binary Tree Postorder Traversal

2015-06-21 23:35 232 查看

题目

Binary Tree Postorder Traversal

Given a binary tree, return the postorder traversal of its nodes’ values.

For example:

Given binary tree {1,#,2,3},

1

\

2

/

3

return [3,2,1].

思路

二叉树的后序遍历,递归和非递归两种。

有一个不用栈的非递归的方法,空间复杂度O(1),可参考:《Morris Traversal方法遍历二叉树(非递归,不用栈,O(1)空间)

递归解法

/**
1. Definition for a binary tree node.
2. public class TreeNode {
3.     int val;
4.     TreeNode left;
5.     TreeNode right;
6.     TreeNode(int x) { val = x; }
7. }
*/
public class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> list = new LinkedList<Integer>();
if (root != null) {
list.addAll(postorderTraversal(root.left));
list.addAll(postorderTraversal(root.right));
list.add(root.val);
}
return list;
}
}


非递归解法

后序遍历的非递归实现是三种遍历方式中最难的一种。因为在后序遍历中,要保证左孩子和右孩子都已被访问并且左孩子在右孩子前访问才能访问根结点,这就为流程的控制带来了难题。

参考:《二叉树的非递归遍历

方法一

对于任一结点P,将其入栈,然后沿其左子树一直往下搜索,直到搜索到没有左孩子的结点,此时该结点出现在栈顶,但是此时不能将其出栈并访问,因此其右孩子还为被访问。所以接下来按照相同的规则对其右子树进行相同的处理,当访问完其右孩子时,该结点又出现在栈顶,此时可以将其出栈并访问。这样就保证了正确的访问顺序。可以看出,在这个过程中,每个结点都两次出现在栈顶,只有在第二次出现在栈顶时,才能访问它。因此需要多设置一个变量标识该结点是否是第一次出现在栈顶。

public class Solution {
private class StackNode {
TreeNode node;
boolean isFirst;
}
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> list = new LinkedList<Integer>();
Stack<StackNode> stack = new Stack<StackNode>();
TreeNode node = root;
StackNode temp;
while (node != null || !stack.empty()) {
while (node != null) {//沿左子树一直往下搜索,直至出现没有左子树的结点
StackNode snode = new StackNode();
snode.node = node;
snode.isFirst = true;
stack.push(snode);
node = node.left;
}
if (!stack.empty()) {
temp = stack.pop();
if (temp.isFirst == true) {//第一次出现在暂定,保留在栈中,访问右孩子
temp.isFirst = false;
stack.push(temp);
node = temp.node.right;
}
else {//第二次出现在栈顶,则弹出栈
list.add(temp.node.val);
}
}
}
return list;
}
}


方法二

第二种思路:要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点P,先将其入栈。如果P不存在左孩子和右孩子,则可以直接访问它;或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。

void postOrder3(BinTree *root)     //非递归后序遍历
{
stack<BinTree*> s;
BinTree *cur;                      //当前结点
BinTree *pre=NULL;                 //前一次访问的结点
s.push(root);
while(!s.empty())
{
cur=s.top();
if((cur->lchild==NULL&&cur->rchild==NULL)||
(pre!=NULL&&(pre==cur->lchild||pre==cur->rchild)))
{
cout<<cur->data<<" ";  //如果当前结点没有孩子结点或者孩子节点都已被访问过
s.pop();
pre=cur;
}
else
{
if(cur->rchild!=NULL)
s.push(cur->rchild);
if(cur->lchild!=NULL)
s.push(cur->lchild);
}
}
}


方法三

很奇妙的一种方法:改造前序遍历来实现。

pre-order traversal is root-left-right, and post order is left-right-root. modify the code for pre-order to make it root-right-left, and then reverse the output so that we can get left-right-root .

Create an empty stack, Push root node to the stack.

Do following while stack is not empty.

2.1. pop an item from the stack and print it.

2.2. push the left child of popped item to stack.

2.3. push the right child of popped item to stack.

reverse the ouput.

方法四

是对方法三的改进。还是将前序遍历顺序改为root-right-left,但是在往List中保存节点 数据时,不采用
list.add()
方法(尾插法),而直接采用LinkedList的头插法:
list.addFirst(node.val)
list.add(0,node.val)
,这样就避免最后再进行反转
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: