[英]Write a non-recursive traversal of a Binary Search Tree using constant space and O(n) run time
这不是作业,这是一个面试问题。
这里的问题是算法应该是恒定的空间。 我对如何在没有堆栈的情况下做到这一点非常无能为力,我会发布我用堆栈编写的内容,但无论如何它都无关紧要。
这是我尝试过的:我试图进行预订遍历,然后我到了最左边的节点,但我被困在那里。 我不知道如何在没有堆栈/父指针的情况下“recurse”备份。
任何帮助,将不胜感激。
(我将它标记为Java,因为这是我很习惯使用的,但它显然是语言无关的。)
我并没有完全认为它,但我认为只要你愿意在这个过程中弄乱你的树,这是可能的。
每个节点都有2个指针,因此它可以用来表示双向链表。 假设你从Root前进到Root.Left = Current。 现在Root.Left指针是无用的,所以将它指定为Current.Right并继续到Current.Left。 当你到达最左边的孩子时,你会有一个链表,树上挂着一些节点。 现在迭代一遍,重复你遇到的每一棵树的过程
编辑:想通了。 这是按顺序打印的算法:
void traverse (Node root) {
traverse (root.left, root);
}
void traverse (Node current, Node parent) {
while (current != null) {
if (parent != null) {
parent.left = current.right;
current.right = parent;
}
if (current.left != null) {
parent = current;
current = current.left;
} else {
print(current);
current = current.right;
parent = null;
}
}
}
Morris Inorder树遍历怎么样? 它基于线程树的概念,它修改了树,但在完成后还原它。
Linkie: http ://geeksforgeeks.org/?p = 6358
不使用任何额外的空间。
如果您使用的是基于向下指针的树,并且没有父指针或其他内存,则无法在恒定空间中遍历。
如果您的二叉树是在数组中而不是基于指针的对象结构中,则可能是这样。 但是,您可以直接访问任何节点。 这是一种作弊行为;-)
这是iluxa 原始答案的缩短版。 它以完全相同的顺序运行完全相同的节点操作和打印步骤 - 但是以简化的方式[1]:
void traverse (Node n) {
while (n) {
Node next = n.left;
if (next) {
n.left = next.right;
next.right = n;
n = next;
} else {
print(n);
n = n.right;
}
}
}
[1]另外,它甚至在树根节点没有左子节点时起作用。
接受的答案需要以下更改,否则它将不会打印BST只有一个节点的树
if (current == NULL && root != NULL)
print(root);
iluxa上面回答的一个小特例
if(current== null)
{
current = root;
parent = current.Right;
if(parent != null)
{
current.Right = parent.Left;
parent.Left = current;
}
}
它是一个搜索树,因此您可以随时获取下一个键/条目
你需要smth(我没有测试代码,但它很简单)
java.util.NavigableMap<K, V> map=...
for (Entry<K, V> e = map.firstEntry(); e!=null; e = map.higherEntry(e.getKey())) {
process(e)
}
为了清楚起见,这是higherEntry
,所以它不是递归的。 你有它 :)
final Entry<K,V> getHigherEntry(K key) {
Entry<K,V> p = root;
while (p != null) {
int cmp = compare(key, p.key);
if (cmp < 0) {
if (p.left != null)
p = p.left;
else
return p;
} else {
if (p.right != null) {
p = p.right;
} else {
Entry<K,V> parent = p.parent;
Entry<K,V> ch = p;
while (parent != null && ch == parent.right) {
ch = parent;
parent = parent.parent;
}
return parent;
}
}
}
return null;
}
问题的标题没有提到节点中缺少“父”指针。 虽然BST不一定需要它,但许多二叉树实现确实有父指针。 class Node {Node * left; 节点*权利; 节点*父节点; 数据数据; };
就是这种情况,在纸上对树进行成像,并在树周围用铅笔绘制,从边缘的两侧上下移动(当向下时,你将被留在边缘,并且上升时,你会在右侧)。 基本上,有4种状态:
Traverse( Node* node )
{
enum DIRECTION {SW, NE, SE, NW};
DIRECTION direction=SW;
while( node )
{
// first, output the node data, if I'm on my way down:
if( direction==SE or direction==SW ) {
out_stream << node->data;
}
switch( direction ) {
case SW:
if( node->left ) {
// if we have a left child, keep going down left
node = node->left;
}
else if( node->right ) {
// we don't have a left child, go right
node = node->right;
DIRECTION = SE;
}
else {
// no children, go up.
DIRECTION = NE;
}
break;
case SE:
if( node->left ) {
DIRECTION = SW;
node = node->left;
}
else if( node->right ) {
node = node->right;
}
else {
DIRECTION = NW;
}
break;
case NE:
if( node->right ) {
// take a u-turn back to the right node
node = node->right;
DIRECTION = SE;
}
else {
node = node->parent;
}
break;
case NW:
node = node->parent;
break;
}
}
}
我们可以在不修改树本身的情况下遍历二叉树(假设节点有父指针)。 它可以在恒定的空间内完成。 我发现这个有用的链接http://tech.technoflirt.com/2011/03/04/non-recursive-tree-traversal-in-on-using-constant-space/
它是一个二叉搜索树,因此可以通过一系列右/左决策来访问每个节点。 将该系列描述为0/1,最低有效位为最重要。 所以函数f(0)的意思是“通过右手分支找到的节点,直到找到一个叶子; f(1)表示左边一个,右边是右边; f(2) - 即二进制010 - - 意味着取右,然后是左,然后是权利,直到你找到一个叶子。迭代f(n)从n = 0开始直到你击中每一片叶子。效率不高(因为你必须从树的顶部开始时间)但恒定的记忆和线性时间。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.