ツリーとして次の構造があると仮定します。
struct Node
{
Node *left;
Node *right;
int value;
};
ツリーをその場で変更する 3 つのパスですべてのペアを印刷できます。right
アイデアは、同じ深さでノードをポインターと一緒にリンクすることです。left
ポインターに従って下にトラバースします。また、各深さのリストを null で終了しないため、深さごとに予想されるノードの数も維持します。次に、解凍してツリーを元の構成に復元します。
これの美しさはzip_down
機能です。左のサブツリーの右の分岐が右のサブツリーの左の分岐を指すように、2 つのサブツリーをまとめて「圧縮」します。すべてのサブツリーに対してこれを行うと、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) スタック スペース。