树的遍历 迭代算法——思路:初始化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考的如何,顺便看一下他考的试题,里面有最后一道题,是关于给出中序遍历和后序遍历然后求一个层次遍历.等等,我找 ...
随机推荐
- xmpp使用经验
IM 标准协议有XMPP\IMPP\PRIM\SIP(SIMPLE)等,其中XMPP基于XML的协议,具备了很好的扩展性(依靠XML的域名空间)并且可以建立在TLS上使用SASL认证. 1.文件比如图 ...
- WebBrowser之获取跳转页面的Document接口源码
问题由来是这样的,今天帮一个网友解决问题,说从VC驿站下载了一个源码,程序的功能主要是在对话框上面放置了一个WebBrowser控件,程序启动的时候默认调用这句代码: m_web.Navigate(_ ...
- 【2018百度之星资格赛】 A 问卷调查 - 位运算&动规
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=6344 参考博客:在此感谢http://www.cnblogs.com/LQLlulu/p/941923 ...
- 2n皇后 - 回溯
题目地址:http://www.51cpc.com/web/problem.php?id=1172 Summarize: 1. 递归回溯: 2. 先扫完一种皇后,再扫描另一种: 3. 循环输入: 4. ...
- ubuntu下手动配置apache2.4.12
(apache2也可以使用 sudo apt-get install apache2来安装,下面来讲解下如何手动安装配置apache2) 在安装apache2之前,先要安装apache2的依赖项,ap ...
- cmake 学习笔记(一) buildsystem
参见网址: http://www.cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html Introduction 基于CMake的构建 ...
- [bzoj4521][Cqoi2016][手机号码] (数位dp+记忆化搜索)
Description 人们选择手机号码时都希望号码好记.吉利.比如号码中含有几位相邻的相同数字.不含谐音不 吉利的数字等.手机运营商在发行新号码时也会考虑这些因素,从号段中选取含有某些特征的号 码单 ...
- SHA256兼容性
SHA-2是一个加密哈希(Cryptographic Hash)函数的一个集合,包括SHA-224,SHA256和SHA-512.在SHA-256中的256代表哈希(Hash)输出或者摘要的位尺寸(即 ...
- 【codeforces 707C】Pythagorean Triples
[题目链接]:http://codeforces.com/contest/707/problem/C [题意] 给你一个数字n; 问你这个数字是不是某个三角形的一条边; 如果是让你输出另外两条边的大小 ...
- Leetcode 132.分割回文串II
分割回文串 给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串. 返回符合要求的最少分割次数. 示例: 输入: "aab" 输出: 1 解释: 进行一次分割就可将 s ...