我最近学习了二叉树,并决定练习一下。我认为我非常理解指针和参考参数,但后来我遇到了这段代码:
void doubleTree(struct node* node) {
struct node* oldLeft;
if (node==NULL) return;
// do the subtrees
doubleTree(node->left);
doubleTree(node->right);
// duplicate this node to its left
oldLeft = node->left;
node->left = newNode(node->data);
node->left->left = oldLeft;
}
我根本无法理解如何在不使用引用参数或非void函数的情况下更改二叉树的构造。
我已经在互联网上搜索了几天,并没有找到合适的解释。 我知道在使用现有节点时我不需要参考参数,但据我所知,这与创建新元素并将其添加到二叉树相同 - 我拥有使用非空函数!
请有人向我解释一下吗?
答案 0 :(得分:0)
好吧,在C中根本没有参考参数......所有参数都按值传递 。出于这个原因,指针就在眼前......你将把一个指针传递给函数,该指针指向子树的根节点,它本身就是对根节点的引用。 这确实是你期望的参考,但表示为节点的指针。
在您显示的情况下,如果您必须更改传递的指针(您无法将其更改为按值)更改为子树的根节点,则可能会出现问题,如更改指针只在子程序中本地发生。在这种情况下,您可以传递双指针,如
void doubleTree(struct node** node) { ... }
所以你实际上传递了指向保存根节点地址的根指针的指针。修改它应该用:
*node = foo ...;
因此,您将引用根指针。但是在例程中完成的事情只处理节点内容和根节点的子节点....没有指向它的指针,所以你根本不需要传递对指针的引用。 / p>
除了您提出的问题之外,所显示的代码存在问题。假设加倍的节点被附加为孙子左 - 左子,而不检查左子是否实际上有左子。在左子节点实际上有一个左子节点的情况下,该点的子树将被新创建的节点替换,产生内存泄漏(从现在开始,所有子树都将无法访问)并将该子树更改为单个节点。应该将树加倍的例程的奇怪行为。
我个人认为使用返回复制树的函数会更好更简单:
struct node* doubleTree(struct node* node)
{
return node != NULL
? newNode(node->data,
doubleTree(node->left),
doubleTree(node->right));
: NULL;
}
(在这种情况下newNode()
有三个参数,即节点数据,要附加到它的左右子节点)
我认为将doubled节点存储为root给定节点的子节点的意图是将构建树保存为给定节点的子树的一些技巧。但由于上述原因,它失败了,所以你需要实际返回一个指针,以便能够回复调用代码。 通过引用旧树和新树传递空节点的代码的意图失败,因为当递归调用时,它应该导致以这种方式构造的所有子树,最终将由填充的空白副本填充树原始和复制子树的左右副本。您应该需要一个递归例程,如上所述,返回对新创建的子树的引用。
你在这一点上的权利:))