迭代后期以穿越没有保留访问标志
-
20-09-2019 - |
题
为什么是必要的,以保持与标志迭代后期以穿越并不序或预先顺序的迭代遍历。
这是可以做到的员额以穿越没有保留访问标志?
解决方案
下面是一个命令后,请访问:
postordervisit(t)
{ if not(leaf(t))
{ postordervisit(left(t);
postordervisit(right(t));
}
L1: process(t);
L2:
}
它不使用任何标志。为什么你认为一个标志是必要的吗?
也许我不明白这句话,“迭代后序遍历”。 根据对称性,如果你认为“迭代序遍历”不需要一个标志, 我主张你不得不相信“迭代后序遍历”也 标志自由的,反之亦然。
编辑:我的坏,必须在夜间迟到。 “迭代”,意思是“没有递归执行”。 OK,让你实现你自己的节点堆栈,和的你要实现什么相当于返回地址的堆栈。我认为标志模拟收益的影响 解决知道是否去L1或L2未来。因为你需要这个职位顺序,由对称你需要它的预购。
编辑2010年10月:我再烂,提供的算法不是后序。修改。
其他提示
后序遍历的迭代版本可以不使用访问标记来实现,这是落实才更困难。
在这里看到迭代后序遍历两种解决方案,而无需使用任何访问标志。
如果我们开始跟简单的递归postorder算法,
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"只能出现 最多一次的顶部栈, 而
- "b"和"c"和出现的任何数量的时间在中间叠,有可能交织的。
因此,我们真的不需要储存"一个"内部的栈单一的变量来储存"一"就足够了。这使我们能够简化的天真的算法迭代进入更传统的形式:
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
.
我发现,在用户的解决方案的问题的 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;
};
我相信算法显示在以前的帖子端口序遍历是因为它“进程”逛左子树前的节点。后序遍历是基本上相同逆波兰表示法,其中操作数(叶节点或子树)先于操作者(下一个较高的子树节点)。
一个校正后序遍历algorith将是:
postordervisit(t)
{ if null(t) return;
postordervisit(right(t));
postordervisit(left(t);
process(t);
}
这会前往子树的根前访问叶或子树节点。
标志是没有必要的,应该避免,因为读取器不应该修改任何东西,任何修改不会允许的并发性,例如。 这里是一个反复的后序的实现遍历在C作为宏。它适用于任何类型的树适当配置,也可以做颠倒后的顺序。整个库,它也实现了一个迭代前序遍历,是这里。
#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)); \
) \
/**/
它可以用来这样。为了得到反转后顺序,重新定义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);
}