寻找一个就地O(N)算法,它为给定的平衡二叉树打印节点对(在遍历树时),如下所示:
a
b c
d e f g
输出:bc,de,ef,fg
其中'a'是根节点,'b'是左子节点,'c'是右节点等。 请注意输出中的'ef'对。
基于以下评论的其他信息:
答案 0 :(得分:3)
如果这个树存储在一个数组中,它可以被重新排列为“水平连续”(第一个元素是根,下两个是它的子节点,接下来的四个是它们的子节点等),问题是微不足道的
如果以其他方式存储,则会出现问题。您可以尝试广度优先遍历,但这会占用O(n)内存。
嗯我想你可以通过存储当前级别和当前元素的路径(表示为二进制数)来创建O(n log n)时间算法,并且只存储最后访问过的元素以便能够创建对。只有O(1 + log n)内存。 - >这可能实际上是一个带回溯的O(n)算法(见下文)。
我知道有一种简单的算法可以在O(n)中按顺序访问所有节点,因此可能有一个技巧可以在O(n)时间内按顺序访问“姐妹”节点。 O(n log n)时间保证,你可以停在给定的水平。
还有一个简单的O(n log n)算法,你只需要过滤给定级别的节点,增加下一个循环的级别。
编辑:
好的,我创建了一个在O(n)中运行的解决方案,其中包含O(1)内存(两个机器字大小的变量,用于跟踪当前和最大级别/技术上是O(log log n)内存,但是让我们掩盖那个/和几个节点,但它要求所有节点都包含指向其父节点的指针。使用这种特殊结构,可以在没有O(n log n)堆栈的情况下进行顺序遍历,仅使用两个节点来向左,向上或向右步进。你停在特定的最高水平,永远不会低于它。您可以跟踪实际和最高级别,以及在最高级别遇到的最后一个节点。显然,如果你在最高级别遇到下一对,你可以打印出这样的对。每当您意识到该级别上没有更多级别时,您就会增加最高级别。
从n-1节点二叉树中的根节点开始,这相当于1 + 3 + 7 + 15 + ... + n-1个操作。这是2 + 4 + 8 + 16 + ... + n - log2n = 2n - log2n = O(n)操作。
如果没有特殊的Node* parent
成员,由于有序遍历所需的堆栈,此算法只能用于O(log n)内存。
答案 1 :(得分:2)
假设您的树具有以下结构:
struct Node
{
Node *left;
Node *right;
int value;
};
您可以在三遍中打印出所有对,修改树。我们的想法是将同一深度的节点与它们的right
指针连接起来。按照left
指针进行遍历。我们还维护每个深度的预期节点数,因为我们不会为每个深度终止列表。然后,我们解压缩以将树恢复到其原始配置。
这就是zip_down
功能的美;它将两个子树“拉链”在一起,使左子树的右分支指向右子树的左分支。如果对每个子树执行此操作,则可以按照right
指针迭代每个深度。
struct Node
{
Node *left;
Node *right;
int value;
};
void zip_down(Node *left, Node *right)
{
if (left && right)
{
zip_down(left->right, right->left);
left->right= right;
}
}
void zip(Node *left, Node *right)
{
if (left && right)
{
zip(left->left, left->right);
zip_down(left, right);
zip(right->left, right->right);
}
}
void print_pairs(const Node * const node, int depth)
{
int count= 1 << depth;
for (const Node *node_iter= node; count > 1; node_iter= node_iter->right, --count)
{
printf("(%c, %c) ", node_iter->value, node_iter->right->value);
}
if (node->left)
{
print_pairs(node->left, depth + 1);
}
}
void generate_tree(int depth, Node *node, char *next)
{
if (depth>0)
{
(node->left= new Node)->value= (*next)++;
(node->right= new Node)->value= (*next)++;
generate_tree(depth - 1, node->left, next);
generate_tree(depth - 1, node->right, next);
}
else
{
node->left= NULL;
node->right= NULL;
}
}
void print_tree(const Node * const node)
{
if (node)
{
printf("%c", node->value);
print_tree(node->left);
print_tree(node->right);
}
}
void unzip(Node * const node)
{
if (node->left && node->right)
{
node->right= node->left->right;
assert(node->right->value - node->left->value == 1);
unzip(node->left);
unzip(node->right);
}
else
{
assert(node->left==NULL);
node->right= NULL;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
char value_generator= 'a';
Node root;
root.value= value_generator++;
generate_tree(2, &root, &value_generator);
print_tree(&root);
printf("\n");
zip(root.left, root.right);
print_pairs(&root, 0);
printf("\n");
unzip(&root);
print_tree(&root);
printf("\n");
return 0;
}
EDIT4:就地,O(n)时间,O(log n)堆栈空间。