2016-03-25 6 views
0

Я реализую кодировщик Хаффмана. Деревья Хаффмана строятся снизу вверх с использованием очереди приоритетов. У меня есть простой класс узлов с указателями на два других узла. Цикл, который строит дерево:самоопределения узла в цикле enqueing

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 так сверху() возвращает константную ссылку, и назначая результат сверху() к константной ссылке или константный указатель делает очередь неизменна.

+1

Адреса '& п1, & n2' аннулируются после' while' цикл влево. Вы имеете дело с оборванными указателями (что бы вы ни делали). –

+0

Если это так, то почему я могу следовать указателям root после завершения цикла? – BenK

ответ

2

Когда у вас есть фигурные скобки {}, вы находитесь в новом объеме. и переменные, объявленные в этой области, являются локальными для этой области и действительны только внутри этой области. Когда область действия заканчивается, то для вас ваш цикл будет каждый раз, когда цикл будет итерации, область исчезнет, ​​а переменные в этой области будут уничтожены и больше не будут существовать.

Сохранение указателя на переменную, которая выходит за пределы области действия, приведет к неопределенным поведением, когда вы попытаетесь разыменовать этот указатель.

0

C++ не содержит сборку мусора и не выделяет объекты на кучу, если вы не сообщите об этом - вам нужно самостоятельно управлять своей памятью.

Если вы хотите построить динамически выделенное дерево, вам нужно явно выделить свои узлы в куче, используя new или некоторую библиотечную библиотеку более высокого уровня. Вам также необходимо убедиться, что они уничтожены, когда вы знаете, что больше нет ссылок на них.

Как уже упоминалось другие, ваши huffnode переменные n1 и n2 локальные переменные и уничтожаются, когда они выходят из области видимости (который, каждый проход вашего while цикла).

+0

Я знаю, что локальные переменные уничтожаются, когда они выходят за пределы области видимости, но мой отладчик показывает, что они всегда имеют одинаковые адреса на каждой итерации. Возможно, компилятор делает это как оптимизацию цикла, поэтому программе не нужно делать дорогие запросы памяти на каждую итерацию. Дело в том, что только потому, что n1 и n2 уничтожаются в конце каждой итерации, это не значит, что они не будут занимать одну и ту же память в начале следующей итерации. – BenK

+1

Но если вы хотите построить дерево из них, вы не можете просто повторно использовать одну и ту же память - вам нужно выделить отдельный объект для каждого узла! В C++, если вы объявляете локальную переменную объекта, * фактический объект * хранится в стеке и фактически уничтожается *, когда он выходит из области видимости. Это отличается от Java, который выделяет все объекты в своей куче, сохраняет только ссылки в своих локальных переменных и будет хранить выделенные объекты до тех пор, пока они не будут собраны в мусор. – comingstorm

+1

Итак, вам нужно выделить каждый отдельный узел (используя 'new'). Ваши локальные переменные должны быть * указателями * (в некотором роде) на объекты, выделенные кучей. – comingstorm

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)); 
}