二叉树中的 "marker for NULL pointers" 是什么?
What are "marker for NULL pointers" in binary tree?
我正在执行 this and this post about binary search tree 实施。
我看到二叉搜索树表示为(例如):
1 5 7 10 40 50
我试图了解相同 here 的序列化或反序列化。博客 post 让我对那些 -1 感到疯狂,他们称之为 空指针标记 。他们将树表示为:
20 8 4 -1 -1 12 10 -1 -1 14 -1 -1 -1
迷茫
那些 -1 是什么?
我的最终目标是使用 C# 将二叉搜索树存储和读取到某种文件,但这种混乱让我望而却步。
并非所有节点都有两个子节点。显然,因为否则树将是无限的。在 runtime/in 内存中,丢失的节点由 nullptr
表示,在磁盘上由 -1
表示。
这些-1
代表没有孩子的地方。
以你为例
20
/
8__
/ \
4 12
/\
10 14
您可以想象在节点没有 children:
的地方添加额外的 -1
(您可以使用树本身不会出现的任何值)
20
/ \
8__ -1
/ \
4 12
/\ /\
-1 -1 10 14
/\ /\
-1 -1 -1 -1
现在,如果您按 "root, then left subtree, then right subtree" 顺序遍历树,您将得到以下字符串:
20 8 4 -1 -1 12 10 -1 -1 14 -1 -1 -1
这正是您所拥有的。所以这是一种用数组形式表示树的方法。同时,很容易从该形式重建树。知道这些 -1
在某种意义上是特殊的,它们不再有 children,您可以从这样的数组中重建树,而不会产生任何歧义。
这些-1
的含义在其他答案中都有解释,我来展示一下读写树的代码:
class Tree
{
public:
int value;
Tree* left;
Tree* right;
Tree(int i_value, Tree* i_left, Tree* i_right)
: value(i_value), left(i_left), right(i_right)
{}
Tree(const Tree&) = delete;
static const int NO_TREE = -1;
template<typename Iterator>
static Tree* Create(Iterator& i_iterator)
{
if (*i_iterator == NO_TREE)
{
i_iterator++;
return nullptr;
}
int value = *(i_iterator++);
Tree* left = Create(i_iterator);
Tree* right = Create(i_iterator);
return new Tree(value, left, right);
}
template<typename Iterator>
static void Write(Tree* i_tree, Iterator& i_iterator)
{
if (i_tree == nullptr)
{
*(i_iterator++) = NO_TREE;
return;
}
*(i_iterator++) = i_tree->value;
Write(i_tree->left, i_iterator);
Write(i_tree->right, i_iterator);
}
};
用法:
vector<int> v = { 20, 8, 4, -1, -1, 12, 10, -1, -1, 14, -1, -1, -1 };
Tree* t = Tree::Create(v.begin());
vector<int> w;
Tree::Write(t, std::back_inserter(w));
我正在执行 this and this post about binary search tree 实施。
我看到二叉搜索树表示为(例如):
1 5 7 10 40 50
我试图了解相同 here 的序列化或反序列化。博客 post 让我对那些 -1 感到疯狂,他们称之为 空指针标记 。他们将树表示为:
20 8 4 -1 -1 12 10 -1 -1 14 -1 -1 -1
迷茫
那些 -1 是什么?
我的最终目标是使用 C# 将二叉搜索树存储和读取到某种文件,但这种混乱让我望而却步。
并非所有节点都有两个子节点。显然,因为否则树将是无限的。在 runtime/in 内存中,丢失的节点由 nullptr
表示,在磁盘上由 -1
表示。
这些-1
代表没有孩子的地方。
以你为例
20
/
8__
/ \
4 12
/\
10 14
您可以想象在节点没有 children:
的地方添加额外的-1
(您可以使用树本身不会出现的任何值)
20
/ \
8__ -1
/ \
4 12
/\ /\
-1 -1 10 14
/\ /\
-1 -1 -1 -1
现在,如果您按 "root, then left subtree, then right subtree" 顺序遍历树,您将得到以下字符串:
20 8 4 -1 -1 12 10 -1 -1 14 -1 -1 -1
这正是您所拥有的。所以这是一种用数组形式表示树的方法。同时,很容易从该形式重建树。知道这些 -1
在某种意义上是特殊的,它们不再有 children,您可以从这样的数组中重建树,而不会产生任何歧义。
这些-1
的含义在其他答案中都有解释,我来展示一下读写树的代码:
class Tree
{
public:
int value;
Tree* left;
Tree* right;
Tree(int i_value, Tree* i_left, Tree* i_right)
: value(i_value), left(i_left), right(i_right)
{}
Tree(const Tree&) = delete;
static const int NO_TREE = -1;
template<typename Iterator>
static Tree* Create(Iterator& i_iterator)
{
if (*i_iterator == NO_TREE)
{
i_iterator++;
return nullptr;
}
int value = *(i_iterator++);
Tree* left = Create(i_iterator);
Tree* right = Create(i_iterator);
return new Tree(value, left, right);
}
template<typename Iterator>
static void Write(Tree* i_tree, Iterator& i_iterator)
{
if (i_tree == nullptr)
{
*(i_iterator++) = NO_TREE;
return;
}
*(i_iterator++) = i_tree->value;
Write(i_tree->left, i_iterator);
Write(i_tree->right, i_iterator);
}
};
用法:
vector<int> v = { 20, 8, 4, -1, -1, 12, 10, -1, -1, 14, -1, -1, -1 };
Tree* t = Tree::Create(v.begin());
vector<int> w;
Tree::Write(t, std::back_inserter(w));