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

树的遍历 迭代算法——思路:初始化stack,pop stack利用pop的node,push new node to stack,可以考虑迭代一颗树 因为后序遍历最后还要要访问根结点一次,所以要访问根结点两次是难点的更多相关文章

  1. 数据结构5_java---二叉树,树的建立,树的先序、中序、后序遍历(递归和非递归算法),层次遍历(广度优先遍历),深度优先遍历,树的深度(递归算法)

    1.二叉树的建立 首先,定义数组存储树的data,然后使用list集合将所有的二叉树结点都包含进去,最后给每个父亲结点赋予左右孩子. 需要注意的是:最后一个父亲结点需要单独处理 public stat ...

  2. 每日一题 - 剑指 Offer 33. 二叉搜索树的后序遍历序列

    题目信息 时间: 2019-06-26 题目链接:Leetcode tag:分治算法 递归 难易程度:中等 题目描述: 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果.如果是则返回 tr ...

  3. 判断序列是否为二叉排序树的后序遍历 python

    题目:给定一个序列,判断其是不是一颗二叉排序树的后序遍历结果 分析:首先要知道什么是排序二叉树,二叉排序树是这样定义的,二叉排序树或者是一棵空树,或者是具有下列性质的二叉树: (1)若左子树不空,则左 ...

  4. 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 题意: 通过一棵二叉树的中序 ...

  5. 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. ...

  6. 剑指Offer - 九度1367 - 二叉搜索树的后序遍历序列

    剑指Offer - 九度1367 - 二叉搜索树的后序遍历序列2013-11-23 03:16 题目描述: 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则输出Yes,否则输出 ...

  7. [LeetCode系列] 从中序遍历和后序遍历序列构造二叉树(迭代解法)

    给定中序遍历inorder和后序遍历postorder, 请构造出二叉树. 算法思路: 设后序遍历为po, 中序遍历为io. 首先取出po的最后一个节点作为根节点, 同时将这个节点入stn栈; 随后比 ...

  8. 小小c#算法题 - 11 - 二叉树的构造及先序遍历、中序遍历、后序遍历

    在上一篇文章 小小c#算法题 - 10 - 求树的深度中,用到了树的数据结构,树型结构是一类重要的非线性数据结构,树是以分支关系定义的层次结构,是n(n>=0)个结点的有限集.但在那篇文章中,只 ...

  9. 根据 中序遍历 和 后序遍历构造树(Presentation)(C++)

    好不容易又到周五了,周末终于可以休息休息了.写这一篇随笔只是心血来潮,下午问了一位朋友PAT考的如何,顺便看一下他考的试题,里面有最后一道题,是关于给出中序遍历和后序遍历然后求一个层次遍历.等等,我找 ...

随机推荐

  1. ssh多主机

    #node1 HOST node1 HostName 10.10.10.10 Port 21 User ubuntu UseKeychain yes AddKeysToAgent yes #node2 ...

  2. ArrayAccess(数组式访问)

    实现该接口后,可以像访问数组一样访问对象. 接口摘要: ArrayAccess { abstract public boolean offsetExists ( mixed $offset ) abs ...

  3. 关于DOS-BOX的使用方法

    将MASM文件夹里的全部文件拷贝到一个目录下,比如E:\masm下,然后将这个目录挂着为DOSBox的一个盘符下,挂载命令为 Mount c e:\masm 切换到E盘 然后编译,运行

  4. php第二十七节课

    注册审核 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3 ...

  5. P4817 [USACO15DEC]Fruit Feast 水果盛宴

    P4817 [USACO15DEC]Fruit Feast 水果盛宴 现在Bessie的饱食度为 00 ,她每吃一个橙子,饱食度就会增加 AA :每吃一个柠檬,饱食度就会增加 BB .Bessie还有 ...

  6. 洛谷——P2018 消息传递

    P2018 消息传递 题目描述 巴蜀国的社会等级森严,除了国王之外,每个人均有且只有一个直接上级,当然国王没有上级.如果A是B的上级,B是C的上级,那么A就是C的上级.绝对不会出现这样的关系:A是B的 ...

  7. UVA12118 Inspector's Dilemma(欧拉路径)

    题目: 某个国家有V(V≤1000)个城市,每两个城市之间都有一条双向道路直接相连,长度为T(每条边的长度都是T).你的任务是找一条最短的道路(起点和终点任意), 使得该道路经过E条指定的边.输出这条 ...

  8. CCF201709-1 打酱油 java(100分)

    试题编号: 201709-1 试题名称: 打酱油 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 小明带着N元钱去买酱油.酱油10块钱一瓶,商家进行促销,每买3瓶送1瓶,或者每 ...

  9. Extract local angle of attack on wind turbine blades

    Extract local angle of attack on wind turbine blades Table of Contents 1. Extract local angle of att ...

  10. 泛型转换https://www.cnblogs.com/eason-chan/p/3633210.html

    import java.lang.reflect.ParameterizedType;import java.lang.reflect.Type;//总结1.st.getClass==Student. ...