2

I am having trouble building my structure of the Huffman tree when decoding.

Right now I am encoding the tree by if it has children making the prefix 0 and if it has no child make it 1.

For example, a tree like (a,b,c,d) would be encoded as 001a1b01c1d and their Huffman code is

00|01|10|11

Note: | was added for clarity and is not actually in the header.

Here’s the tree in a graphical form:

    / \
   /\ /\
  a b c d

Right now when I am trying to rebuild the tree using 001a1b01c1d, The problem I am having trouble is recreating the tree properly because I am unsure what to check for when going back up to the tree (how far to go up).

Here is the code the index was only added just to try the word 'random' obviously it doesn't work for other cases. I am thinking of using the depth of the tree somehow

void Tree::build(std::queue<char> encodedHeader) {
    char currentChar;
    this -> thisRoot = new HCNode(0, '\0',0,0,0);
    HCNode * newRoot = new HCNode (0,'\0',0,0,0);
    HCNode * childZero = new HCNode (0, '\0', 0,0,0);
    HCNode * childOne = new HCNode (0, '\0', 0,0,0);
    childZero -> p = newRoot;
    childOne -> p = newRoot;
    newRoot -> c0 = childZero;
    newRoot -> c1 = childOne;
    this -> foreverRoot = newRoot;

    while(!header.empty()) {
        currentChar = header.front();
        header.pop();
        if(currentChar != '\n') {
            if (currentChar == '0') {
                HCNode * childZero = new HCNode (0, '\0', 0,0,0);
                HCNode * childOne = new HCNode (0, '\0', 0,0,0);
                child0 -> p = newRoot;
                child1 -> p = newRoot;
                newRoot -> c0 = childZero;
                newRoot -> c1 = childOne; 

                currentChar = header.front();
                while (currentChar == '0') {
                    newRoot = newRoot -> c0;
                    header.pop();
                    currentChar = header.front();
                    HCNode * childZero = new HCNode (0, '\0', 0,0,0);
                    HCNode * childOne = new HCNode (0, '\0', 0,0,0);
                    childZero -> p = newRoot;
                    childOne -> p = newRoot;
                    newRoot -> c0 = childZero;
                    newRoot -> c1 = childOne;  
                }
            }
            else {
                currentChar = header.front();
                header.pop();

                if(newRoot -> c0 != NULL) {
                    newRoot -> c0 -> symbol = currentChar;
                    newRoot = newRoot -> c1;
                }
                else {
                    newRoot -> symbol = currentChar;
                    while(newRoot -> p != NULL && index != 2) {
                        index++;
                        newRoot = newRoot -> p;
                    }
                    index = 0;
                    newRoot = newRoot -> c1;
                }
            }
        }
    }
Brendan Long
  • 53,280
  • 21
  • 146
  • 188
PictureMeAndYou
  • 533
  • 2
  • 5
  • 16
  • 1
    I'd guess if you have problems with your code, you should at least show part of it. Otherwise how can we be helpful by means of [tag:c++] code? You want to tag [tag:algorithm] solely eventually? – πάντα ῥεῖ Oct 28 '14 at 19:32
  • before building that tree, or trying to code an algorithm, you should first understand why you need to do that and what that is representing . http://www.youtube.com/results?search_query=computerphile+huffman – user2485710 Oct 28 '14 at 19:40
  • I would say go up to the next right child. But your tree encoding method seems strange. – Jarod42 Oct 28 '14 at 19:41
  • The compressed file should start with a header containing the histogram of the symbols (i.e., letter count), followed by the encoded data. – barak manos Oct 28 '14 at 19:42
  • 1
    In order to create the tree, you need to read the histogram, create a node for each letter, add the nodes one by one into a minimum binary heap (minimum by letter-count), then do the following: Extract the first two elements from the heap, create a parent node for them (smaller node as left child, larger node as right child). The "letter-count" of the parent should be the sum of its children's. Insert the parent node into the heap and repeat the process until the heap contains only one element, which is the root of your tree. – barak manos Oct 28 '14 at 19:42
  • Here is something that I implemented a long time ago (not using STL), which you might find helpful: https://github.com/barakman/Huffman. – barak manos Oct 28 '14 at 19:46
  • Before I answer, let me make sure I understand: you want to take a string like "001a1b01c1d" and use it to build a decoding tree? – Taylor Brandstetter Oct 28 '14 at 19:53
  • @πάνταῥεῖ yes I uploaded the code and tagged algorithim – PictureMeAndYou Oct 28 '14 at 20:21
  • @TaylorBrandstetter Yes exactly I have an array of chars of "001a1b01c1d" and use it to build a decoding tree. Just the structure of the tree. I have the algorithm to actually decode the tree. My structure is just wrong – PictureMeAndYou Oct 28 '14 at 20:23

2 Answers2

1

I literally just wrote some code to do this as an exercise, and you're using the exactly same header format as I did. The trick I found was that this is much easier to implement recursively, as in:

Node read_tree(some_input input, string current_code = "") {
    Node node;
    if (input.readchar() == '0') {
        node.left = read_tree(input, current_code + "0");
        node.left.parent = node;
        node.right = read_tree(input, current_code + "1");
        node.right.parent = node;
    } else {
        node.code = input.readchar();
    }
    return node;
}

Obviously you'll need to do something similar using your own more realistic types, but the basic idea should work.

Brendan Long
  • 53,280
  • 21
  • 146
  • 188
  • I am trying to understand this way. Would you mind explaining your code in terms of the way I am doing it. I know it should be recursive, but it isn't clear how you implement it your way – PictureMeAndYou Nov 05 '14 at 17:25
  • @PictureMeAndYou yedidya's answer seems to be similar to mine, but using your classes. The main difference is that your code is not recursive and mine is, and that lets me get rid of almost all of your code. – Brendan Long Nov 05 '14 at 20:48
-1

first of all, i'm very sorry about my english (it's not my mother tongue :-). Generally it is recommended to solve trees problems by recursion and this is a good advice here too. here is a code that i think can be work (i didn't test it so maybe it will need a bit work):

buildTree(std::queue<char> header, HCNode* node)
{
     char currentChar = header.front();
     header.pop();
     if(currentChar == '0')
     {
          childZero -> p = newRoot;
          childOne -> p = newRoot;
          node->c0 = new HCNode (0, '\0', 0,0,0);
          node->c1 = new HCNode (0, '\0', 0,0,0);
          node->c0->p = node;
          node->c1->p = node;
          buildTree(header, node->c0); // this is the recurtion
          buildTree(header, node->c1); // this is the recurtion too
     }
     else // currentChar == '1'
     {
          currentChar = header.front();// currentChar = symbol
          header.pop();
          node-> symbol = currentChar;
     }
}
void Tree::build(std::queue<char> encodedHeader)
{
    this->foreverRoot = new HCNode(0, '\0',0,0,0);
    buildTree(header, foreverRoot);
}

i'm hope it will be helpfull. good luck.

yedidya
  • 1
  • 1