-> grandma
-> dad
-> me
-> sister
-> niece
-> brother
-> uncle
-> cousin
我有一个结构如下
struct Node{
Node *parent;
Node *next;
Node *child;
}
我如何释放该链表? 我的想法是先进行深度搜索并取消分配每个节点吗?
答案 0 :(得分:4)
递归深度搜索(DFS):你是对的,这是处理二进制树内存的好方法:
remove(node):
if node is null: return
//else
remove(left node)
remove(right node)
free(node)
迭代解决方案:
https://codegolf.stackexchange.com/questions/478/free-a-binary-tree
由于您不想使用任何递归解决方案,因此您可以找到描述良好的迭代解决方案。
答案 1 :(得分:2)
您可以优化树的分配/取消分配。
想象一下,你想创建20或30人的树。您可以分配30个Node
结构的数组:
size_t currentArraySize = 30;
Node* nodes = (Node*)malloc(currentArraySize * sizeof(Node));
size_t nextFreeIndex = 0;
要添加新元素,您可以编写简单的函数:
Node* allocateNode()
{
// Oops! There's not more memory in the buffer.
// Lets increase its size.
if (nextFreeIndex >= currentArraySize) {
currentArraySize *= 2;
Node* newNodes = (Node*)realloc(nodes, currentArraySize * sizeof(Node));
// Should correct pointers (thanks to user3386109)
if (newNodes != nodes) {
for (size_t i = 0; i < nextFreeIndex; i++) {
if (newNodes[i]->parent != NULL)
newNodes[i]->parent -= nodes += newNodes;
if (newNodes[i]->next != NULL)
newNodes[i]->next -= nodes += newNodes;
if (newNodes[i]->child != NULL)
newNodes[i]->child -= nodes += newNodes;
}
}
}
return nodes[nextFreeIndex++];
}
要解除分配所有节点,您只需free
单个指针nodes
。
现在代码看起来有些可怕,因为写了user3386109,所以我们可以稍微简化一下:
Node* allocateNode()
{
// Oops! There's not more memory in the buffer.
// Lets increase its size.
if (nextFreeIndex >= currentArraySize) {
currentArraySize *= 2;
Node* newNodes = (Node*)realloc(nodes, currentArraySize * sizeof(Node));
// Should correct pointers (thanks to user3386109)
if (newNodes != nodes)
correctPointers(newNodes, nodes);
}
return nodes[nextFreeIndex++];
}
#define correctPointer(pointer, oldOffset, newOffset) if (pointer != NULL) { \\
pointer -= oldOffset; \\
pointer += newOffset; \\
}
void correctPointers(Node* newNodes, Node* nodes)
{
for (size_t i = 0; i < nextFreeIndex; i++) {
correntPointer(newNodes[i]->parent, nodes, newNodes);
correntPointer(newNodes[i]->child, nodes, newNodes);
correntPointer(newNodes[i]->next, nodes, newNodes);
}
}
答案 2 :(得分:1)
迭代版,灵感来自Day-Stout-Warren算法:
void removetree(Node *node)
{
while(node != NULL)
{
Node *temp = node;
if(node->child != NULL)
{
node = node->child;
temp->child = node->next;
node->next = temp;
}
else
{
node = node->next;
remove(temp);
}
}
}
这个算法有点像尝试将树转换为与next
指针单链接的列表,这很容易通过迭代取消链接和销毁第一个项目来销毁。但是它永远不会完成转换,因为它尽可能地取消链接并删除头节点,尽管其余的树尚未转换。也就是说,它将 relink 步骤与 unlink-and-destroy 步骤交错。
我们使用if
指令测试第一个(头部)节点是否有子节点。如果是这样,我们将其子项设为新头,当前节点成为新头next
节点。这样,我们在第一级列表中还有一个next
链接。 now-head节点的“下一个”成为前一个节点的子节点,现在是头部的第一个next
。
另一方面,如果头节点没有子节点,则可能会将其删除,并且next
成为新头。
这两个步骤由while
循环迭代,直到所有子节点都转换为兄弟节点并随后删除。
答案 3 :(得分:-3)
您可以使用递归解决方案
free(root)
{
if (root->next == null)
{
free(node)
}
free(root->left)
free(right->)
}