144. Binary Tree Preorder Traversal

Given a binary tree, return the preorder traversal of its nodes' values.

For example:
Given binary tree [1,null,2,3],

   1
\
2
/
3

return [1,2,3].

Note: Recursive solution is trivial, could you do it iteratively?

# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None class Solution(object):
def preorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
ans = []
if root is None:
return ans
# init stack
stack = [root] # pop stack and push new node to it
while stack:
node = stack.pop()
ans.append(node.val)
if node.right:
stack.append(node.right)
if node.left:
stack.append(node.left)
return ans

94. Binary Tree Inorder Traversal

Given a binary tree, return the inorder traversal of its nodes' values.

For example:
Given binary tree [1,null,2,3],

   1
\
2
/
3

return [1,3,2].

Note: Recursive solution is trivial, could you do it iteratively?

# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None class Solution(object):
def inorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
ans = []
if not root:
return ans
# init stack
stack = []
node = root
while node:
stack.append(node)
node = node.left # pop node from stack and push node to stack
while stack:
node = stack.pop()
ans.append(node.val)
node = node.right
while node:
stack.append(node)
node = node.left
return ans

145. Binary Tree Postorder Traversal

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

For example:
Given binary tree [1,null,2,3],

   1
\
2
/
3

return [3,2,1].

Note: Recursive solution is trivial, could you do it iteratively?

迭代的后序遍历是比较难的,但是有简单解法,那就是实际上它做的是反向的先序遍历。亦即遍历的顺序是:节点 -> 右子树 -> 左子树。这生成的是后序遍历的逆序输出。

# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None class Solution(object):
def postorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
if not root:
return []
stack = [root]
ans = [] while stack:
node = stack.pop()
ans.append(node.val)
if node.left:
stack.append(node.left)
if node.right:
stack.append(node.right)
return ans[::-1]

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

第一种思路:对于任一结点P,将其入栈,然后沿其左子树一直往下搜索,直到搜索到没有左孩子的结点,此时该结点出现在栈顶,但是此时不能将其出栈并访问,因此其右孩子还为被访问。

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

void PostOrderDev(TreeNode *root)
{
if(root == NULL)
{
debug <<"The tree is NULL..." <<endl;
} stack<TreeNode *> nstack;
TreeNode *node = root; while(node != NULL || nstack.empty( ) != true)
{ // 遍历直至最左节点
while(node != NULL)
{
node->isFirst = 1; // 当前节点首次被访问
nstack.push(node);
node = node->left;
} if(nstack.empty() != true)
{
node = nstack.top( );
nstack.pop( ); if(node->isFirst == 1) // 第一次出现在栈顶
{ node->isFirst++;
nstack.push(node); node = node->right;
}
else if(node->isFirst == 2)
{
cout <<node->val;
node = NULL;
}
}
}
}

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

void PostOrderDev(TreeNode *root)
{
if(root == NULL)
{
debug <<"The tree is NULL..." <<endl;
} stack<TreeNode *> nstack; TreeNode *cur; //当前结点
TreeNode *pre = NULL; //前一次访问的结点
nstack.push(root); while(nstack.empty( ) != true)
{
cur = nstack.top( ); if((cur->left == NULL && cur->right == NULL) // 左右还是均为NULL, 可以被输出
|| (pre != NULL && ((pre == cur->left && cur->right == NULL) || pre == cur->right))) // 左右还是被输出了, 递归返回
// 其实当前节点要是想被输出, 要么
// 1--其左右孩子均为NULL
// 2--其左孩子刚被输出,而其右孩子为NULL
// 3--其右孩子刚被输出
//
// 但是这里有一个优化, 入栈时候, 先是根入栈, 然后是右孩子, 然后是左孩子,
// 因此当跟元素位于栈顶的时候, 其左右孩子必然已经弹出,即被输出,
// 也就是说, 当前
{
cout<<cur->val; //如果当前结点没有孩子结点或者孩子节点都已被访问过
nstack.pop( );
pre = cur;
}
else
{
// 由于栈是先进后出,因此先如后孩子, 再左孩子可以保证递归返回时先遍历左孩子
if(cur->right != NULL)
{
nstack.push(cur->right);
} if(cur->left != NULL)
{
nstack.push(cur->left);
}
}
}
}

其实后序遍历中当前节点要是想被输出, 要么

  1. 其左右孩子均为NULL

  2. 其左孩子刚被输出,而其右孩子为NULL

  3. 其右孩子刚被输出

但是这里有一个优化, 入栈时候, 先是根入栈, 然后是右孩子, 然后是左孩子,

因此当跟元素位于栈顶的时候, 其左右孩子必然已经弹出,即被访问并且输出,

也就是说, 判断当前节点是否需要输出时,只需要之前被输出的节点pre是当前栈定节点cur的孩子就行

即后序遍历中当前栈顶元素要是想被输出

  1. 其左右孩子均为NULL

  2. 其孩子(不论左右)刚被输出即可

而且如果刚被输出的节点是其左孩子,那么我们可以确定其有孩子必为NULL,否则它后于父节点入栈,应该在父节点之前被弹出并且输出

因此我们的输出判断可以改为

        if((cur->left == NULL && cur->right == NULL)                     //  左右还是均为NULL, 可以被输出
|| (pre != NULL && ((pre == cur->left /*&& cur->right == NULL*/) || pre == cur->right))) // 其孩子刚被被输出了, 递归返回
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None class Solution(object):
def postorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
if not root:
return []
stack = [root]
ans = [] accessed_node = None
while stack:
node = stack[-1]
if (not node.left and not node.right) or (accessed_node and (accessed_node is node.left or accessed_node is node.right)):
stack.pop()
accessed_node = node
ans.append(node.val)
else:
if node.right:
stack.append(node.right)
if node.left:
stack.append(node.left)
return ans

最新文章

  1. Mysql - 数据库操作
  2. C# 目录(文件夹)复制实现
  3. C# RFID windows 服务 串口方式
  4. 【转】用ASP.NET加密Cookie数据
  5. Message,MessageQueue,Looper,Handler ——由view.post(runnable想到的)
  6. 不可或缺的企业OA面临问题,以及解决建议 软件定制开发 森普演示平台
  7. List集合对象中的排序,随机显示
  8. 最多两次股票交易-Best Time to Buy and Sell Stock III
  9. Github创建分支
  10. 混合高斯模型(GMM)推导及实现
  11. 简单来说一下ui-route
  12. phthon网络编程
  13. Asp.net core Razor 页面
  14. 同步博客—CSDN推广
  15. hbase 集群管理脚本
  16. Kubernetes集群部署关键知识总结
  17. nginx(二)nginx的安装
  18. Vue脚手架使用步骤 2.9.6版本
  19. K2在Gartner 2017 iBPMS魔力象限报告中上升为“挑战者”
  20. 11代理模式Proxy

热门文章

  1. JavaScipt30(第一个案例)(主要知识点:键盘事件以及transitionend)
  2. ThinkPHP---layer插件
  3. ERROR: Field &#39;PostId&#39; doesn&#39;t have a default value Exception in thread &quot;main&quot; org.hibernate.exception.GenericJDBCException: could not execute statement
  4. 【计算几何】二维凸包——Graham&#39;s Scan法
  5. linux常用操作记录
  6. Pycharm Anaconda 安装dlib
  7. 运行/调试你的PHP代码
  8. CCF201612-2 工资计算 java(100分)
  9. mysql批量替换某个字段的部分内容
  10. LINUX-用户和群组