如何从文件重建BST < >我的C++程序从用户输入创建一个不平衡的BST,并保存它做磁盘。它首先通过对每个节点进行预排序遍历并为每个节点分配一个唯一的编号来索引每个节点。接下来,它将BST输出到一个文件。它通过执行预排序遍历,然后为每个节点打印数据值、左子节点的索引号和右子节点的索引号来实现这一点
因此,BST保存到磁盘后,内存中的BST将被销毁。我想读入该文件并重新创建BST,这样它将与以前完全一样。假设您没有达到最佳绑定,可以使用此简单算法如何从文件重建BST < >我的C++程序从用户输入创建一个不平衡的BST,并保存它做磁盘。它首先通过对每个节点进行预排序遍历并为每个节点分配一个唯一的编号来索引每个节点。接下来,它将BST输出到一个文件。它通过执行预排序遍历,然后为每个节点打印数据值、左子节点的索引号和右子节点的索引号来实现这一点,c++,file,indexing,linked-list,binary-tree,C++,File,Indexing,Linked List,Binary Tree,因此,BST保存到磁盘后,内存中的BST将被销毁。我想读入该文件并重新创建BST,这样它将与以前完全一样。假设您没有达到最佳绑定,可以使用此简单算法 nodes_list = [] For each line i: Search for node i in nodes_list if(found): node_i = found_node node_i.set_value(line_value) else: node_i =
nodes_list = []
For each line i:
Search for node i in nodes_list
if(found):
node_i = found_node
node_i.set_value(line_value)
else:
node_i = new node(i)
node_i.set_value(line_value)
nodes_list.add(node_i)
Search for line_left_node in nodes_list
if(found):
node_i.set_left_node(found_node)
else:
left_node = new node(line_left_node)
node_i.set_left_node(left_node)
nodes_list.add(left_node)
Search for line_right_node in nodes_list
if(found):
node_i.set_right_node(found_node)
else:
right_node = new node(line_right_node)
node_i.set_right_node(right_node)
nodes_list.add(right_node)
假设你没有达到最佳界限,你可以使用这个简单的算法
nodes_list = []
For each line i:
Search for node i in nodes_list
if(found):
node_i = found_node
node_i.set_value(line_value)
else:
node_i = new node(i)
node_i.set_value(line_value)
nodes_list.add(node_i)
Search for line_left_node in nodes_list
if(found):
node_i.set_left_node(found_node)
else:
left_node = new node(line_left_node)
node_i.set_left_node(left_node)
nodes_list.add(left_node)
Search for line_right_node in nodes_list
if(found):
node_i.set_right_node(found_node)
else:
right_node = new node(line_right_node)
node_i.set_right_node(right_node)
nodes_list.add(right_node)
将所有节点连同左、右子索引(比如哈希表)一起读入内存。然后从根节点(文件中的第一个节点)开始,通过哈希表中的索引查找左、右子节点。以DFS或BFS方式对子节点重复相同的过程。两者都应该有效
您可以对此进行优化,以避免在构建树之前将整个数据加载到内存中。您可以读取节点并以DFS方式构造树。所以,添加left child很简单。添加正确的子项时,必须检查索引号。如果不匹配,请尝试将该子节点添加到高于DFS排序中当前节点的节点中。将所有节点连同左、右子索引一起读取到内存中(如哈希表)。然后从根节点(文件中的第一个节点)开始,通过哈希表中的索引查找左、右子节点。以DFS或BFS方式对子节点重复相同的过程。两者都应该有效
您可以对此进行优化,以避免在构建树之前将整个数据加载到内存中。您可以读取节点并以DFS方式构造树。所以,添加left child很简单。添加正确的子项时,必须检查索引号。如果不匹配,请尝试将该子节点添加到高于DFS排序中当前节点的节点中。Postorder会更简单。您只需将恢复的节点推送到堆栈上,要链接到父节点的子节点将始终是堆栈的最顶层条目
您也只需要一次过程,只要您在每个节点上记录保存了哪些子节点,以便知道要从堆栈中弹出什么以及要分配哪些子节点 后序将更简单。您只需将恢复的节点推送到堆栈上,要链接到父节点的子节点将始终是堆栈的最顶层条目
您也只需要一次过程,只要您在每个节点上记录保存了哪些子节点,以便知道要从堆栈中弹出什么以及要分配哪些子节点 假设您知道前面的树(N)的大小。也许这是文件的第一行。如果没有,则可以很容易地对此进行调整,以动态地重新调整索引向量的大小。请注意,这是半伪代码:
// Only needed while parsing the file
std::vector<Node*> index(N, NULL);
// We can always create the root node.
// This simplifies the while loop below.
index[0] = createNode(0);
while (!in.eof()) {
int nodeID = -1, leftID = -1, rightID = -1;
parseNode(in, &nodeID, &leftID, &rightID);
// Guaranteed to be non-NULL
Node* node = index[nodeID];
// if leftID or rightID is -1, createNode()
// will simply return NULL.
index[leftID] = createNode(leftID);
index[rightID] = createNode(rightID);
node->setLeftChild(index[leftID]);
node->setRightChild(index[rightID]);
}
假设您知道前面的树(N)的大小。也许这是文件的第一行。如果没有,则可以很容易地对此进行调整,以动态地重新调整索引向量的大小。请注意,这是半伪代码:
// Only needed while parsing the file
std::vector<Node*> index(N, NULL);
// We can always create the root node.
// This simplifies the while loop below.
index[0] = createNode(0);
while (!in.eof()) {
int nodeID = -1, leftID = -1, rightID = -1;
parseNode(in, &nodeID, &leftID, &rightID);
// Guaranteed to be non-NULL
Node* node = index[nodeID];
// if leftID or rightID is -1, createNode()
// will simply return NULL.
index[leftID] = createNode(leftID);
index[rightID] = createNode(rightID);
node->setLeftChild(index[leftID]);
node->setRightChild(index[rightID]);
}
如果将二叉搜索树存储为预顺序遍历,那么在读取元素时,只需一次插入一个元素即可得到的树将与开始时的树相同。这当然需要O(n logn)时间。如果您愿意存储外部节点(null),则可以执行以下操作:
ReadBSTPreOrder(node ** target) {
node * n = readNode();
*target = n;
if (n == NULL) return;
ReadBSTPreOrder(&node->left);
ReadBSTPreOrder(&node->right);
}
这还有一个额外的优点,就是可以处理不属于BST的二叉树。
如果您愿意使用表示法,那么可以使用单个位存储空值,但是空值的单字节标记和记录的不同标记就可以了。这也可以避免您写出索引。如果您将二叉搜索树存储为预顺序遍历,那么您只需在读取时一次插入一个元素即可得到的树将与开始时的树相同。这当然需要O(n logn)时间。如果您愿意存储外部节点(null),则可以执行以下操作:
ReadBSTPreOrder(node ** target) {
node * n = readNode();
*target = n;
if (n == NULL) return;
ReadBSTPreOrder(&node->left);
ReadBSTPreOrder(&node->right);
}
这还有一个额外的优点,就是可以处理不属于BST的二叉树。
如果您愿意使用表示法,那么可以使用单个位存储空值,但是空值的单字节标记和记录的不同标记就可以了。这也可以避免您写出索引。您能解释一下“行”是什么意思吗?您能解释一下“行”是什么意思吗?这需要存储外部节点。考虑退化二叉树(本质上是链表)。如果要存储外部节点,则只需预先安排即可。读取左子项的自递归,右子项的递归。如果基本情况只是一个外部节点(即NULL),但不确定您得到的是什么,则每个子节点的存在将是节点数据中的2位。但是我承认,正如您的回答所示,预排序也可以一次完成。这需要存储外部节点。考虑退化二叉树(本质上是链表)。如果要存储外部节点,则只需预先安排即可。读取左子项的自递归,右子项的递归。如果基本情况只是一个外部节点(即NULL),但不确定您得到的是什么,则每个子节点的存在将是节点数据中的2位。但是我承认,正如您的回答所示,预排序也可以一次完成。只为节点中的每个子节点记录一点比较简单,仅当特定子节点存在时才递归+无论如何,1.注意:递归可能是大树深度(堆栈溢出)的问题。如果这是一个问题,您可以将递归算法转换为等效的迭代算法,维护您自己的基于堆的堆栈(例如,请参阅我的答案)