此add_node函数会导致内存问题吗?

Will this add_node function cause memory issues?

本文关键字:内存 问题 add node 函数      更新时间:2023-10-16

我写了一个递归函数来在二叉搜索树中插入一个新节点。函数给出如下。

void add_node(node *it, int val)
{
node * temp = new node;
temp->data=val;
temp->left=NULL;
temp->right=NULL;
if(root==NULL)
{
root=temp;
}
else if(it->data > val)
{
if(it->left==NULL)
{
it->left=temp;
return;
}
else
add_node(it->left, val);
}
else
{
if(it->right==NULL)
{
it->right=temp;
return;
}
else
add_node(it->right, val);
}
}

此函数每次递归调用时都会创建一个临时节点。如果BST的高度很大,这会导致一些问题(与内存有关)吗?

此函数每次递归调用时都会创建一个临时节点。

该节点分配不是临时的;它是完全泄露的。唯一保留的是最后一个。事实上,任何需要多个跃点的遍历都会泄漏激活堆栈中任何先前递归调用中的节点分配。

有两件事使这个问题可以解决。

  1. 在知道节点要挂在哪里之前,不要分配节点。
  2. 相关,不要针对某些外部root编码。使用对指针的引用作为输入参数类型,允许您直接在树中引用实际指针(而不仅仅是它们包含的地址)。这包括root指针。

假设一个看起来像这样的node结构(偏执地删除复制 ctor 和赋值):

struct node
{
node(int val)
: value(val)
, left(nullptr)
, right(nullptr)
{
std::cout << "node::node(" << value << ")n";
}
node(const node&) = delete;
node& operator=(const node&) = delete;
int value;
node *left;
node *right;
};

我们可以像这样制作一个简单的节点插入:

// note reference-to-pointer as first arg type
void add_node(node *& refp, int value) 
{
if (refp == nullptr)
{
refp = new node(value);
}
else if (value < refp->value)
{
add_node(refp->left, value);
}
else
{
add_node(refp->right, value);
}
}

就是这样。一旦我们最终知道事情的发展方向,一次分配。对于某些外部root指针没有特殊情况,并且更容易阅读和理解。


完整示例

添加上面的nodeadd_node定义、无序打印遍历和清理free_tree,下面是一个示例:

#include <iostream>
#include <random>
struct node
{
node(int val)
: value(val)
, left(nullptr)
, right(nullptr)
{
std::cout << "node::node(" << value << ")n";
}
node(const node&) = delete;
node& operator=(const node&) = delete;
int value;
node *left;
node *right;
};
void add_node(node *& refp, int value)
{
if (refp == nullptr)
{
refp = new node(value);
}
else if (value < refp->value)
{
add_node(refp->left, value);
}
else
{
add_node(refp->right, value);
}
}
void inorder(const node* root)
{
if (root)
{
inorder(root->left);
std::cout << root->value << ' ';
inorder(root->right);
}
}
void free_tree(node *& root)
{
if (root)
{
free_tree(root->left);
free_tree(root->right);
delete root;
root = nullptr;
}
}
int main()
{
node *root = nullptr;
std::mt19937 rng{ std::random_device{}() };
std::uniform_int_distribution<> dist(1, 99);
for (int i = 0; i < 20; ++i)
add_node(root, dist(rng));
inorder(root);
std::cout.put('n');
free_tree(root);
}

输出{显然有所不同)

node::node(79)
node::node(28)
node::node(39)
node::node(82)
node::node(10)
node::node(11)
node::node(22)
node::node(4)
node::node(19)
node::node(85)
node::node(38)
node::node(66)
node::node(45)
node::node(15)
node::node(23)
node::node(73)
node::node(52)
node::node(45)
node::node(73)
node::node(84)
4 10 11 15 19 22 23 28 38 39 45 45 52 66 73 73 79 82 84 85