树的遍历 迭代算法——思路:初始化stack,pop stack利用pop的node,push new node to stack,可以考虑迭代一颗树 因为后序遍历最后还要要访问根结点一次,所以要访问根结点两次是难点
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);
}
}
}
}
其实后序遍历中当前节点要是想被输出, 要么
其左右孩子均为NULL
其左孩子刚被输出,而其右孩子为NULL
其右孩子刚被输出
但是这里有一个优化, 入栈时候, 先是根入栈, 然后是右孩子, 然后是左孩子,
因此当跟元素位于栈顶的时候, 其左右孩子必然已经弹出,即被访问并且输出,
也就是说, 判断当前节点是否需要输出时,只需要之前被输出的节点pre是当前栈定节点cur的孩子就行
即后序遍历中当前栈顶元素要是想被输出
其左右孩子均为NULL
其孩子(不论左右)刚被输出即可
而且如果刚被输出的节点是其左孩子,那么我们可以确定其有孩子必为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
树的遍历 迭代算法——思路:初始化stack,pop stack利用pop的node,push new node to stack,可以考虑迭代一颗树 因为后序遍历最后还要要访问根结点一次,所以要访问根结点两次是难点的更多相关文章
- 数据结构5_java---二叉树,树的建立,树的先序、中序、后序遍历(递归和非递归算法),层次遍历(广度优先遍历),深度优先遍历,树的深度(递归算法)
1.二叉树的建立 首先,定义数组存储树的data,然后使用list集合将所有的二叉树结点都包含进去,最后给每个父亲结点赋予左右孩子. 需要注意的是:最后一个父亲结点需要单独处理 public stat ...
- 每日一题 - 剑指 Offer 33. 二叉搜索树的后序遍历序列
题目信息 时间: 2019-06-26 题目链接:Leetcode tag:分治算法 递归 难易程度:中等 题目描述: 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果.如果是则返回 tr ...
- 判断序列是否为二叉排序树的后序遍历 python
题目:给定一个序列,判断其是不是一颗二叉排序树的后序遍历结果 分析:首先要知道什么是排序二叉树,二叉排序树是这样定义的,二叉排序树或者是一棵空树,或者是具有下列性质的二叉树: (1)若左子树不空,则左 ...
- POJ 1240 Pre-Post-erous! && East Central North America 2002 (由前序后序遍历序列推出M叉树的种类)
题目链接:http://poj.org/problem?id=1240 本文链接:http://www.cnblogs.com/Ash-ly/p/5482520.html 题意: 通过一棵二叉树的中序 ...
- POJ 1240 Pre-Post-erous! && East Central North America 2002 (由前序后序遍历序列推出M叉树的种类)
题目链接 问题描述 : We are all familiar with pre-order, in-order and post-order traversals of binary trees. ...
- 剑指Offer - 九度1367 - 二叉搜索树的后序遍历序列
剑指Offer - 九度1367 - 二叉搜索树的后序遍历序列2013-11-23 03:16 题目描述: 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则输出Yes,否则输出 ...
- [LeetCode系列] 从中序遍历和后序遍历序列构造二叉树(迭代解法)
给定中序遍历inorder和后序遍历postorder, 请构造出二叉树. 算法思路: 设后序遍历为po, 中序遍历为io. 首先取出po的最后一个节点作为根节点, 同时将这个节点入stn栈; 随后比 ...
- 小小c#算法题 - 11 - 二叉树的构造及先序遍历、中序遍历、后序遍历
在上一篇文章 小小c#算法题 - 10 - 求树的深度中,用到了树的数据结构,树型结构是一类重要的非线性数据结构,树是以分支关系定义的层次结构,是n(n>=0)个结点的有限集.但在那篇文章中,只 ...
- 根据 中序遍历 和 后序遍历构造树(Presentation)(C++)
好不容易又到周五了,周末终于可以休息休息了.写这一篇随笔只是心血来潮,下午问了一位朋友PAT考的如何,顺便看一下他考的试题,里面有最后一道题,是关于给出中序遍历和后序遍历然后求一个层次遍历.等等,我找 ...
随机推荐
- CAD绘制自定义实体(com接口)
在cad使用过程中,用户可以绘制自定义实体.点击此处下载演示实例. 调用DrawCustomEntity函数,绘制一个自定义实体对象. 下面代码绘制一个自定义实体,C#代码实现如下: private ...
- 【转载】Spring注解@Resource和@Autowired区别对比
@Resource和@Autowired都是做bean的注入时使用,其实@Resource并不是Spring的注解,它的包是javax.annotation.Resource,需要导入,但是Sprin ...
- Linux kernel-汇编基础
mov ASSEMABLE C LANGUAGE movl %eax,%edx edx = eax; --->register mode movl $0x123,%edx edx = 0x123 ...
- 浅析Oracle中的不等于号
前几天碰到一个关于Oracle不等于的问题,最后搜索了一下,发现下面资料,拿来跟大家分享一下,需要的朋友可以参考下 关于Oracle中的不等于号: 在Oracle中, <> != ...
- java string与byte互转
1.string 转 byte[]byte[] midbytes=isoString.getBytes("UTF8");//为UTF8编码byte[] isoret = srt2. ...
- java中通用权限管理设计(转)
原文地址:http://www.cnblogs.com/a7345678/archive/2008/09/25/1298838.html 转自博客园暗夜精灵-鬼才阁 实现业务系统中的用户权限管理 B/ ...
- 51nod 1241 特殊的排序
[题解] 设满足前后两个元素之差为1的最长上升子序列LIS的长度为m,那么本题的答案即为n-m. 证明: 1,n-m次移动一定可以让序列递增.设LIS的第一个数为i,最后一个数为j,我们按照i-1到1 ...
- [模拟赛FJOI Easy Round #2][T3 skill] (最小割+最大权闭合子图(文理分科模型))
[题目描述] 天上红绯在游戏中扮演敏剑,对于高攻击低防御的职业来说,爆发力显得非常重要,为此,她准备学习n个技能,每个技能都有2个学习方向:物理攻击和魔法攻击.对于第i个技能,如果选择物理攻击方向,会 ...
- Shiro-工作流程
[与Web集成] 1.Shiro 提供了与 Web 集成的支持,其通过一个ShiroFilter 入口来拦截需要安全控制的URL,然后进行相应的控制. 2.ShiroFilter 类似于如 Strut ...
- 九度oj 题目1059:abc
题目1059:abc 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:4510 解决:3546 题目描述: 设a.b.c均是0到9之间的数字,abc.bcc是两个三位数,且有:abc+bcc ...