Я пытаюсь написать функцию, которая принимает дерево хаффмана и символ. Затем он должен кодировать символ и возвращать его.
Код до сих пор:
string encode(NodePtr root, char letter)
{
string encode_str; //a string which will store the encoded string
NodePtr tempNode = root; //Initialize a new Huffman to be used in this function
NodePtr tempLeft = root->left;
NodePtr tempRight = root->right;
//A while loop that goes on until we find the letter we want
while((tempLeft->letter != letter) || (tempRight->letter != letter))
{
if((tempRight->is_leaf()) && (tempRight->letter == letter)) //check if is leaf and is letter
{
encode_str = encode_str + '1';
}
else if ((tempLeft->is_leaf()) && (tempLeft->letter == letter)) //check if is leaf and is letter
{
encode_str = encode_str + '0';
}
else if ((tempRight->is_leaf()) && (tempRight->letter != letter)) //check if is leaf and is NOT letter
{
tempNode = root->left;
tempLeft = tempNode->left;
tempRight = tempNode->right;
encode_str = encode_str + '0';
}
else if ((tempLeft->is_leaf()) && (tempLeft->letter != letter)) //check if is leaf and is NOT letter
{
tempNode = root->right;
tempLeft = tempNode->left;
tempRight = tempNode->right;
encode_str = encode_str + '1';
}
}
return encode_str;
}
Это пока не сработало, и отладка тоже мне не помогла. Может ли кто-нибудь помочь мне здесь или, по крайней мере, сказать мне, правильно ли я думаю.
Если ни tempLeft, ни tempRight не является листом, у вас есть бесконечный цикл:
while((tempLeft->letter != letter) || (tempRight->letter != letter))
{
if((tempRight->is_leaf()) &&
(tempRight->letter == letter))
{
// no
}
else if ((tempLeft->is_leaf()) &&
(tempLeft->letter == letter))
{
// no
}
else if ((tempRight->is_leaf()) &&
(tempRight->letter != letter))
{
// no
}
else if ((tempLeft->is_leaf()) &&
(tempLeft->letter != letter))
{
// no
}
}
Там должно быть что-то, что вы намереваетесь сделать в случае, когда узлы не являются листьями. Может быть, рекурсия?
(По комментариям) Возможно, вы работаете с вариантом деревьев Хаффмана, в котором вы можете гарантировать, что каждый узел является либо листом, либо имеет один лист. Если вы можете это гарантировать, то вышесказанное не имеет значения (было бы полезно выбросить исключение, если оно произойдет). Однако у реальных деревьев Хаффмана нет этого свойства.
Когда один ребенок является листом, а другой не является вашим целевым письмом, вы tempNode
установить новый tempNode
, tempLeft
и tempRight
для следующего перехода вокруг цикла.
else if ((tempRight->is_leaf()) &&
(tempRight->letter != letter))
{
tempNode = root->left;
tempLeft = tempNode->left;
tempRight = tempNode->right;
encode_str = encode_str + '0';
}
Однако, поскольку вы никогда не изменяете root
, tempNode = root->left
всегда будет устанавливать tempNode
на тот же узел.
Вероятно, вы хотите tempNode = tempNode->left
.
Чтобы избежать повторения кода, вы можете перемещаться
tempLeft = tempNode->left;
tempRight = tempNode->right;
... быть первым, что происходит в цикле while()
.
Вы говорите, что отладка не помогла. Вы действительно запускаете его в отладчике?
Напишите единичный тест, который устанавливает ваше дерево; подтверждает, что дерево фактически содержит то, что вы намереваетесь; и вызывает эту функцию одной буквой. Решите, как вы думаете, что выполнение должно продолжаться. Теперь запустите код в отладчике, пройдя через него. Когда он перестает делать то, что, по вашему мнению, должен, вы сможете рассуждать о том, почему.
Общим способом реализации кодирования Хаффмана является наличие массива листовых узлов, поэтому вы можете достичь узла через простой доступ к массиву:
NodePtr nodeA = nodes[0];
... и иметь указатель на родительский элемент в каждом узле и поле, указывающее, является ли он левым или правым дочерним, так что вы можете легко пересечь дерево назад, от листа к корню, создавая код (в обратном порядке):
string code = "";
NodePtr node = nodeA;
while(node->parent != NULL) {
code = node->code + code;
node = node->parent;
}