在C语言中重新分配二叉树结构
struct Node{
Node *parent;
Node *next;
Node *child;
}
我试着释放一棵二叉树。我遇到的问题是分配的对象是5520,而对自由函数的调用次数是2747。我不知道为什么,它真的应该释放并遍历树中的所有节点,这是我使用的代码
int number_of_iterations =0;
int number_of_deletions =0;
void removetree(Node *node)
{
number_of_iterations++;
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);
number_of_deletions++
}
}
}
迭代次数为5440,删除次数为2747。
新固定代码:密码正确吗?
const Node *next(const Node *node)
{
if (node == NULL) return NULL;
if (node->child) return node->child;
while (node && node->next == NULL) {
node = node->parent;
}
if (node) return node->next;
return NULL;
}
for ( p= ctx->obj_root; p; p = next(p)) {
free(p);
}
9条答案
按热度按时间bbmckpt71#
如果您的节点确实包含有效的
parent
指针,那么整个过程可以以一种更加紧凑和可读的方式完成。liwlm1x92#
这是一棵二叉树!因为你选择的名字让人们感到困惑,
next
在链表中很常见,但类型才是最重要的,你有一个节点引用了两个完全相同的节点类型,这才是最重要的。取自此处:https://codegolf.stackexchange.com/a/489/15982你链接到。我将
left
重命名为child
,将right
重命名为next
:)at0kjp5o3#
我知道这是一个老帖子,但我希望我的回答能在将来帮助到别人。下面是我在C++中实现的BinaryTree及其操作,没有递归,逻辑可以很容易地在C中实现。
每个节点都拥有一个指向父节点的指针,以使事情变得更容易。
注意:用于打印树内容的inorderPrint()函数使用递归。
输出:
rn0zuynd4#
首先要说的是,如果你试图用非递归的方法来解决递归问题,你会遇到麻烦。
我看到一个错误的答案被选为好的答案,所以我会试着展示我的方法:
我将开始使用指针引用而不是普通指针,因为传递根指针引用可以更容易地检测(和更新)指向根节点的指针。因此,例程的接口将是:
它表示对指向根节点的指针的引用。我将下降到节点,如果
child
或next
中的一个是NULL
,那么这个节点可以通过使引用指针指向另一个链接来自由消除(所以我不会丢失它)。如果节点有两个子节点(child
和next
都是!= NULL
),那么我不能删除这个节点,直到其中一个分支折叠,然后我选择其中一个分支并移动引用(我声明了ref
参数const
以确保我不会修改它,所以我为此使用另一个 moving 引用)然后,算法如下:
我已经在一个完整的例子中包含了这个算法,向您展示了部分树和
moving_ref
在树中移动时的位置。它还显示了删除它所需的刀路。qlvxas9a5#
为什么不递归地做呢?
x8diyxa76#
该实现不适用于根为
1
的树,该树只有一个子树2
。执行
Removetree(NodeOne)
不会在NodeOne
上调用remove
。hc2pp10m7#
我会的
非递归版本:
我想这应该能行
l5tcr1uw8#
您只释放子树,而不是父节点。假设
child
表示节点的left
子节点,next
是right
子节点。然后,您的代码变为:每次while循环完成一次迭代时,左子节点将没有指向它的指针。以下面的树为例:
当
node
是根节点时,会发生以下情况node
指向“% 1”temp
指向“% 1”node
现在指向“2”temp->left
现在指向“5”node->right
现在指向“1”在下一次迭代中,您开始使用指向'2'的
node
和temp
。如您所见,您没有删除节点“% 1”。这将重复。为了解决这个问题,如果希望避免递归,您可能需要考虑使用BFS和类似队列的结构来删除所有节点。
编辑BFS方式:
1.创建队列结构
Q
1.将根节点
node
添加到Q
1.将
node
的左节点添加到Q
1.将
node
的右节点添加到Q
1.释放
node
并将其从Q
中删除1.设置
node
=Q
的第一个元素1.重复步骤3-6,直到
Q
变为空这使用了队列是FIFO结构的事实。
brc7rcf09#
起初,我认为@AnT建议的代码是不正确的,因为我认为这个问题是关于一个以通常方式定义的二叉树(即每个节点都引用其左子树和右子树)。此为虚妄。)假设,结果是节点在其左子树被遍历和释放之后立即被释放,但在右子树发生相同的情况之前。然后,当从右子树向上时,我们将踩在已经被释放的父节点上。
我忽略的是,在最初的问题中,二叉树被表示为一个通用的二叉树,以单向链表的队列的形式,具有到父节点的额外的内部链接。为了清楚起见,我绘制了下图,其中虚线表示对父代的引用。
如果有人仍然关心,有一个正确的方法在通常的形式二叉树。但它仍然需要父链接。用C89写的
直接取自我自己的项目Gena。