为什么有必要为迭代后序遍历保留访问标志,而不是为了顺序或预先迭代遍历。
是否可以在不保留访问标记的情况下进行邮购顺序?
答案 0 :(得分:2)
可以在不使用访问标志的情况下实现后序遍历迭代版本,实现起来更加困难。
请参阅此处,了解迭代后序遍历的两种解决方案,而不使用任何访问过的标记。
http://www.leetcode.com/2010/10/binary-tree-post-order-traversal.html
答案 1 :(得分:1)
如果我们从简单的递归后序算法开始,
def postorder1(node, f):
# a:
if node is None:
return None
postorder1(node.left, f)
# b:
postorder1(node.right, f)
# c:
f(node)
我们可以将函数分为“a”,“b”和“c”三部分,然后通过模拟虚拟调用堆栈将其简单地转换为迭代算法:
def postorder2(node, f):
stack = [("a", node)]
while stack:
go, node = stack.pop()
if go == "a":
if node is not None:
stack.append(("b", node))
stack.append(("a", node.left))
elif go == "b":
stack.append(("c", node))
stack.append(("a", node.right))
elif go == "c":
f(node)
由此我们观察到堆栈只能以三种方式之一进行修改:
[…, a] → […, b, a]
[…, b] → […, c, a]
[…, c] → […]
这意味着:
因此,我们并不需要在堆栈中存储“a” - 存储“a”的单个变量就足够了。这使我们能够将朴素的迭代算法简化为更传统的形式:
def postorder3(node, f):
stack = []
while True:
if node:
stack.append((True, node))
node = node.left
elif stack:
left, top = stack.pop()
if left:
stack.append((False, top))
node = top.right
else:
f(top)
else:
break
堆栈上的布尔标志是“访问标志”。在此示例中,我们不将标志直接存储在节点上,而是存储在堆栈中,但净效果是相同的。该算法的某些变体使用“最后访问过的节点”变量,但这需要一种比较节点“身份”(指针/引用相等)的方法,我们在此不假设。
此标志是算法的必要部分,因为如前面的分析中所述,堆栈中的“b”和“c”条目可以完全任意的方式出现。我们需要某些类型的信息告诉我们是否应该向右移动或致电f
。
答案 2 :(得分:0)
这是一次订单后访问:
postordervisit(t)
{ if not(leaf(t))
{ postordervisit(left(t);
postordervisit(right(t));
}
L1: process(t);
L2:
}
它不使用任何标志。为什么你认为有必要举旗?
也许我不明白这句话,“迭代后订单遍历”。 通过对称性,如果您认为“迭代前序遍历”不需要标记, 我认为你必须相信“迭代后序遍历”也是 国旗免费,反之亦然。
编辑:我的坏,一定是深夜。 “迭代”意思是“没有递归的实现”。 好的,所以你实现了自己的节点堆栈,和你必须实现相当于一堆返回地址的节点。我认为旗帜正在模拟回归的效果 知道下一步是去L1还是L2的地址。因为你需要这个用于下订单,所以你需要它来预订。编辑2010年10月:我的又坏了,提供的算法不是下订单。修改。
答案 3 :(得分:0)
我相信先前发布的端口顺序遍历的算法显示在访问左子树之前“处理”节点。 Postorder Traversal与反向波兰表示法基本相同,其中操作数(叶节点或子树)位于运算符(下一个更高的子树节点)之前。
更正的后序遍历算法将是:
postordervisit(t)
{ if null(t) return;
postordervisit(right(t));
postordervisit(left(t);
process(t);
}
这将在访问子树的根之前访问叶子树或子树节点。
答案 4 :(得分:0)
我在用户 1337c0d3r 的解决方案中发现了一个问题:它只是一个反向顺序的预订单。我的解决方案使用“活动列表”来标记堆栈中的节点。
(您可以将标记标记存储在堆栈中。将单独发布该解决方案。)
void print_postorder(Nodes const& roots)
{
typedef std::set<Node const*> ActiveList;
ActiveList activeNodes;
vector<Nodes::const_iterator> stack(1, roots.begin());
while( stack.empty() == false )
{
Nodes::const_iterator node = stack.back();
ActiveList::iterator activeEntry = activeNodes.find( &*node );
if( activeEntry == activeNodes.end() )
{
// This node is now active.
activeNodes.insert( &*node );
// Plan to visit each child.
for( Nodes::const_reverse_iterator rchild = node->children.rbegin();
rchild != node->children.rend(); ++rchild )
{
Nodes::const_reverse_iterator rchild2 = rchild;
Nodes::const_iterator child = (++rchild2).base();
stack.push_back(child);
}
}
else
{
// Post-order visit the node.
std::size_t depth = activeNodes.size();
for( std::size_t i = 0; i < 4 * depth; ++i )
cout << ' '; // Indent
cout << node->name << endl;
// We're finished with this node.
activeNodes.erase( activeEntry );
stack.pop_back();
}
}
}
// Try this for yourself! Tree representation:
#include <vector>
#include <set>
struct Node;
typedef std::vector<Node> Nodes;
struct Node
{
std::string name;
Nodes children;
};
答案 5 :(得分:0)
标记不是必需的,应该避免,因为读者不应该修改任何东西,例如,任何修改都不允许并发。 Here是C中作为宏的迭代后遍历的实现。它适用于具有适当配置的任何树类型,也可以执行相反的后顺序。整个库(还实现了迭代的预遍历)为here。
#define W_TREE_FOR_EACH_POSTORDER(T,Child,self) \
W_DECLARE(W_CAT(Child,po1), T *Child) \
W_DECLARE(W_CAT(Child,po2), T* W_ID(node) = (self)) \
W_DECLARE(W_CAT(Child,po3), T** W_ID(stack) = NULL ) \
W_DECLARE(W_CAT(Child,po9), int W_ID(_finish_) = 0 ) \
if (W_ID(node) == NULL) \
; \
else \
W_BEFORE(W_CAT(Child,po4), goto W_LABEL(6,Child); ) \
while (!W_ID(_finish_)) \
W_BEFORE (W_CAT(Child,po5), \
W_LABEL(6,Child): \
while (W_ID(node)) { \
BOOST_PP_IF(W_REVERSED, \
W_TREE_FOR_EACH_IMMEDIATE_REVERSED(T,W_CAT(Child,_child), W_ID(node)) \
if (W_CAT(Child,_child,_ix) < W_TREE_GET_DEGREE(W_ID(node))-1) \
W_DYNAMIC_STACK_PUSH( W_ID(stack),W_CAT(Child,_child) ); \
W_DYNAMIC_STACK_PUSH( W_ID(stack),W_ID(node) ); \
W_ID(node) = W_TREE_NEXT_RIGHTMOST(W_ID(node)); \
, /* else */ \
W_TREE_FOR_EACH_IMMEDIATE(T,W_CAT(Child,_child), W_ID(node)) \
if (W_CAT(Child,_child,_ix) > 0) \
W_DYNAMIC_STACK_PUSH( W_ID(stack),W_CAT(Child,_child) ); \
W_DYNAMIC_STACK_PUSH( W_ID(stack),W_ID(node) ); \
W_ID(node) = W_TREE_NEXT_LEFTMOST(W_ID(node)); \
) \
} \
W_ID(node) = W_DYNAMIC_STACK_POP( W_ID(stack) ); \
BOOST_PP_IF(W_REVERSED, \
if (W_ID(node) && W_TREE_NEXT_LEFTMOST(W_ID(node)) \
&& W_DYNAMIC_STACK_PEEK_SAFE(W_ID(stack),NULL) == W_TREE_NEXT_LEFTMOST(W_ID(node)) ) { \
W_DYNAMIC_STACK_POP(W_ID(stack)); \
W_DYNAMIC_STACK_PUSH( W_ID(stack),W_ID(node) ); \
W_ID(node) = W_TREE_NEXT_LEFTMOST(W_ID(node)); \
goto W_LABEL(6,Child); \
} \
, /* else */ \
if (W_ID(node) && W_TREE_NEXT_RIGHTMOST(W_ID(node)) \
&& W_DYNAMIC_STACK_PEEK_SAFE(W_ID(stack),NULL) == W_TREE_NEXT_RIGHTMOST(W_ID(node)) ) { \
W_DYNAMIC_STACK_POP(W_ID(stack)); \
W_DYNAMIC_STACK_PUSH( W_ID(stack),W_ID(node) ); \
W_ID(node) = W_TREE_NEXT_RIGHTMOST(W_ID(node)); \
goto W_LABEL(6,Child); \
} \
) \
Child = W_ID(node); \
W_ID(node) = NULL; \
) \
W_AFTER(W_CAT(Child,po8), \
W_ID(_finish_) = W_DYNAMIC_STACK_IS_EMPTY(W_ID(stack)); \
if (W_ID(_finish_)) \
W_DYNAMIC_STACK_FREE(W_ID(stack)); \
) \
/**/
可以like this使用它。要反转后置顺序,请将W_REVERSED
重新定义为1。要更改下一个字段获取操作,请重新定义W_TREE_NEXT(tree,ix)
,对于可变度数树,请重新定义W_TREE_GET_DEGREE(tree)
。
#include <wondermacros/tree/for_each.h>
struct bintree {
struct bintree* next[2];
const char* value;
};
struct bintree* root = ...
W_TREE_FOR_EACH_POSTORDER(struct bintree, node, root) {
printf("%s\n", node->value);
}