void MultiMap::insert(string key, unsigned int value)
{
if(head == nullptr)
head = new Node(key, value);
else
{
Node* tempNode = head;
while(tempNode != nullptr)
{
if(key <= tempNode->m_key)
tempNode = tempNode->m_left;
else if(key > tempNode->m_key)
tempNode = tempNode->m_right;
}
/*line 1*/tempNode = new Node(key, value);
//*line 2*/head->m_left = new Node(key, value);
}
}
对于赋值,我必须创建一个二叉树类,“MultiMap”,其中包含一个包含字符串和int的节点。
以上是将新节点插入树中的代码。节点按字符串排序。如果我尝试插入的节点的字符串是&gt;当前节点,程序应该尝试将其插入树的右侧分支,如果它是&lt; =,程序应该尝试将其插入树的左侧分支。
我通过尝试按顺序插入两个节点:(Joe,5)和(Bill,1)来测试它,所以如果程序正常工作,“bill”应该在“joe”的左侧分支上。 / p>
第2行被注释掉了。
如果我使用第1行,程序会编译并“插入”第二个节点,但是当我尝试使用其他代码查找它时,它只会找到一个nullptr。如果我用第2行替换第1行,程序将按预期工作。
“tempNode”是我用来跟踪树以找到插入新节点的适当位置的方法。 “head”是指向树中第一个节点的指针。 “m_left”和“m_right”是指向节点的指针,分别代表节点的左右分支。
我不知道为什么这两行不会做同样的事情,即使在那一点上,似乎tempNode和head-&gt; m_left指向内存中的相同位置:第一个的左分支节点
答案 0 :(得分:1)
指针是保留地址的变量。他们没有什么魔力。第1行执行此操作:
tempNode = new Node(key, value);
这不会在树中插入任何内容。实际上,它只会泄漏内存。
tempNode
指向之前此语句的内容无关紧要。更重要的是, tempNode
如何保持先前的值已经丢失,因为您已经从树下降了一级。保持相同地址的两个指针只意味着可以使用两个指针访问该地址。为指针分配新地址对先前寻址的实体(如果有的话)无效。
您的任务应该是找到应该用新分配的对象的地址填充的指针。你找到了(有点)。不幸的是,一旦你走进树中进行最后的零检测,你也会丢失它。一旦这个:
while (tempNode != nullptr)
变得虚假而且破裂,你已经是一个节点太远了。有很多方法可以解决这个问题。有些人喜欢使用“父”指针,但这只意味着你需要特殊情况下的空映射条件。请考虑一下:
void MultiMap::insert(string key, unsigned int value)
{
// pp will always point to the pointer we're testing
// i.e. a pointer to pointer.
Node **pp = &head;
while (*pp) // while whatever pp points to is a non-null-pointer
{
if (key < (*pp)->m_key)
pp = &(*pp)->m_left; // put address of left-pointer into pp
else if ((*pp)->m_key < key)
pp = &(*pp)->m_right; // put address of right pointer into pp
else break; // strict weak order match
}
if (*pp)
{
// found matching key. NOTE: unclear if you wanted to just update or not
}
else
{
// allocate new node.
*pp = new Node(key,value);
}
}
除了用头节点指针的地址初始化指针到指针之外,你会注意到,不再引用head。
最后,注意没有特殊情况的头节点测试。如果映射为空且头指针为NULL,则会自动创建一个新节点并使其成为根节点。
答案 1 :(得分:1)
这里发生了什么:
Node* tempNode = head;
while(tempNode != nullptr)
{
if(key <= tempNode->m_key)
tempNode = tempNode->m_left;
else if(key > tempNode->m_key)
tempNode = tempNode->m_right;
}
好的,现在是tempNode == nullptr
,它没有指向树的任何节点。因为它是堆栈上的变量,所以下一行:
/*line 1*/tempNode = new Node(key, value);
只是初始化这个本地指针而不会影响树本身。(这里真的是内存泄漏。) 在第二行中,初始化树中的节点:
head->m_left = new Node(key, value);
但仅限于head-&gt; m_left。 所以你可以写:
if (key <= tempNode->m_key) {
if (tempNode->m_left == nullptr) {
tempNode->m_left = new Node(key, value);
break; // traverse tree loop
} else {
tempNode = tempNode->m_left;
}
}