我正在实现一个霍夫曼编码器。使用优先级队列自下而上构建霍夫曼树。我有一个简单的节点类,其中包含指向其他两个节点的指针。 构建树的循环是:
while(q.size() > 1)
{
huffnode n1 = q.top();
q.pop();
huffnode n2 = q.top();
q.pop();
q.push(huffnode((char)0, n1.freq+n2.freq, &n1, &n2));
}
循环终止时的剩余节点是树根。
这段代码看起来很无辜,但是在我的测试输入中它给出了一个树,其中根的右子指向自己和根的左子而不是刚刚弹出的两个节点从队列中。我已确认队列已正确排序。
我认为正在发生的是n1和n2是局部变量,它们总是具有相同的地址,如调试器中所示。按下新节点时,它指向这些地址。当该节点稍后弹出时,其副本将被放入其中一个地址中,其中一个地址已经指向,因此它最终指向自身。
我该如何解决这个问题?我无法生成n1和n2指针,因为它们必须是const
,因为top()返回一个const引用,并将top()的结果赋给const引用或const指针使得队列不可变。
答案 0 :(得分:2)
当你有大括号{}
时,你处于一个新的范围内。和在该范围内声明的变量是该范围的本地变量,并且仅在该范围内有效。当范围结束时,每次循环迭代时你的循环就会出现,范围就会消失,并且该范围内的变量将被破坏而不再存在。
当您尝试取消引用该指针时,保存指向超出范围的变量的指针将导致未定义的行为。
答案 1 :(得分:0)
C ++没有垃圾收集,除非你告诉它,否则不会在堆上分配对象 - 你需要自己管理你的内存。
如果要构建动态分配的树,则需要使用new
或某些更高级别的库工具明确地在堆上分配节点。当你知道没有更多的引用时,你还需要确保它们被销毁。
正如其他人所提到的,您的huffnode
变量n1
和n2
是局部变量,当它们超出范围时会被销毁(即{{1}的每一遍循环)。
答案 2 :(得分:0)
new
。
固定代码是
while(q.size() > 1)
{
huffnode* n1 = new huffnode(q.top().data, q.top().freq, q.top().left, q.top().right);
q.pop();
huffnode* n2 = new huffnode(q.top().data, q.top().freq, q.top().left, q.top().right);
q.pop();
q.push(huffnode((char)0, n1->freq + n2->freq, n1, n2));
}