Кодирование бинарного дерева Хаффмана

0

Я пытаюсь написать функцию, которая принимает дерево хаффмана и символ. Затем он должен кодировать символ и возвращать его.

Код до сих пор:

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

Это пока не сработало, и отладка тоже мне не помогла. Может ли кто-нибудь помочь мне здесь или, по крайней мере, сказать мне, правильно ли я думаю.

Теги:
binary-tree
huffman-code

1 ответ

2
Лучший ответ

Если ни 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;
    }
  • 0
    Я думал, что root-> left или root-> right всегда был листом? Я основал это на этом. Таким образом, мой план состоял в том, чтобы проверить, был ли это лист и посмотреть, соответствовало ли письмо. Если нет, то он «идет по пути», а не снова, и пытается снова. Может быть, добавить кодировать (tempNode, буква), если! = Буква?
  • 0
    Примеры, например, в Википедии показывают узлы с двумя дочерними не листовыми объектами: en.wikipedia.org/wiki/File:Huffman_tree_2.svg - но вы, возможно, создали дерево со специальными свойствами, которые вы описываете; в этом случае следуйте шагам отладки, которые я описал.
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню