Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Infinite Recursion, StackOverError in huffman tree

I am working on a Huffman Encoding program and I am almost finished but I am stuck in an infinite recursion loop. Does anyone have an idea where this is going wrong?

This is the error I am getting:

Exception in thread "main" java.lang.StackOverflowError
at sun.nio.cs.SingleByteEncoder.encodeLoop(SingleByteEncoder.java:130)
at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:544)
at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:252)
at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:106)
at java.io.OutputStreamWriter.write(OutputStreamWriter.java:190)
at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:111)
at java.io.PrintStream.write(PrintStream.java:476)
at java.io.PrintStream.print(PrintStream.java:619)
at java.io.PrintStream.println(PrintStream.java:756)
at HuffmanNode.buildTree(hw4.java:63)
at HuffmanNode.buildTree(hw4.java:64)
at HuffmanNode.buildTree(hw4.java:64)
at HuffmanNode.buildTree(hw4.java:64)
at HuffmanNode.buildTree(hw4.java:64)
at HuffmanNode.buildTree(hw4.java:64)
at HuffmanNode.buildTree(hw4.java:64)
at HuffmanNode.buildTree(hw4.java:64)

and the output is continually 5:1, 5:4, 5:2, repeating

my datafile looks like this:

a
a
a
a
d
d
d
d
d
d
d
d
k
k
k
k
k
k
f
f
f
f
f
f
h
h
h
h
h
h
b
b
b
b
b
b
b
b
n
n
n
n
n
n
n
e
e
e
e
e
i
i
i
i
i
i
i
i
l
k
j
a
n
s
g
l
k
j
a
s
v
o
i
j
a
s
d
l
k
g
k
n
m
a
s
d
k
l
o
v
h
a
s
d
g
z

and my code is

    import java.util.*;
import java.io.*;

class HuffmanNode implements Comparable<HuffmanNode>{
HuffmanNode right;
HuffmanNode left;
HuffmanNode parent;
int count;          
String letter;

public HuffmanNode(){}

public HuffmanNode (String letter, int count){
this.letter = letter;
this.count = count;
}
public HuffmanNode (String letter, int count, HuffmanNode parent, HuffmanNode left, HuffmanNode right){
    this.letter = letter;
    this.count = count;
    this.left = left;
    this.right = right;
    this.parent = parent;
}

public void setCount(int count){
this.count = count;
}

public int getCount(){
return count;
}

public void setRight(HuffmanNode right){
this.right = right;
}

public HuffmanNode getRight(HuffmanNode right){
return right;
}

public void setLeft(HuffmanNode left){
this.left = left;
}

public HuffmanNode getLeft(HuffmanNode left){
return left;
}       
public void setParent(HuffmanNode right){
this.left = left;
}   
public HuffmanNode getParent(HuffmanNode parent){
return parent;
}

public void buildTree(HuffmanNode node){
    if (node.compareTo(this) <= 0 && left != null){
    System.out.println(node.getCount() + ":" + this.count);
    left.buildTree(node);
    }
    else if (node.compareTo(this) <= 0 && left == null){
    this.left = node;
    node.parent = this;
    }
    else if (node.compareTo(this) > 0 && right != null){
    System.out.println(node.getCount() + ":" +this.count);
    right.buildTree(node);
    }
    else if (node.compareTo(this) > 0 && right == null){
    this.right = node;
    node.parent = this;
    }
}


public int compareTo(HuffmanNode x){
return this.count - x.count;
}
public void genCode(String s){
    if(left != null){
    left.genCode(s + "0");
    }
    if(right != null){
    right.genCode(s + "1"); 
    }
    if (left == null && right == null){
    System.out.println(s);
    }
}
}

public class hw4{
public static void main (String []args)throws IOException{

//ask user to enter file name
System.out.printf("Enter a file location and name to encode [press Enter]: ");
Scanner input = new Scanner(System.in);
String filename = input.next();

//Gets file name from Scanner and checks to see if valid
File file = new File(filename);
//if (!file.isFile()){
//System.out.printf("Enter a file location and name to encode [press Enter]: ");
//}
Scanner text = new Scanner(file);

String[] letters = {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"};
int[] freq = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

String letter;
String tempStr;
int tempInt;

    while(text.hasNext()){
        letter = text.next();
        //System.out.printf("%s\n", letter);

                    char c = letter.charAt(0);
        int index = c - 97;
        freq[index]++;     
    }

    for(int i=0; i <25; i++){
    System.out.printf("%s:%d\n", letters[i], freq[i]);
    }
    System.out.printf("\n");

    for (int n=0; n <25; n++) {
        for (int i=0; i <25; i++) {
            if (freq[i] > freq[i+1]) {
                // exchange elements
                tempInt = freq[i];  
                tempStr = letters[i]; 
                freq[i] = freq[i+1];
                letters[i] = letters[i+1];  
                freq[i+1] = tempInt;
                letters[i+1] = tempStr;
            }
        }   
       } 

    PriorityQueue<HuffmanNode> huffmanList = new PriorityQueue<HuffmanNode>();

    for(int i=0; i <26; i++){
    System.out.printf("%s:%d\n", letters[i], freq[i]);
        if(freq[i] > 0){
        huffmanList.add(new HuffmanNode(letters[i],freq[i]));
        }
    }

    HuffmanNode root = new HuffmanNode();

    while(huffmanList.size() > 1){
    HuffmanNode x = huffmanList.poll();
    HuffmanNode y = huffmanList.poll();
    HuffmanNode result = new HuffmanNode("-", x.getCount() + y.getCount(), null, x, y);
        if(root == null){
        root = result;
        }
        else{
        root.buildTree(result); 
        }
    huffmanList.add(result);                    
    }
     root.genCode(" ");
}
}
like image 291
user1093111 Avatar asked Dec 07 '12 07:12

user1093111


1 Answers

Your tree-building is at fault.

while(huffmanList.size() > 1){
    HuffmanNode x = huffmanList.poll();
    HuffmanNode y = huffmanList.poll();

You take the two lightest trees from the queue,

    HuffmanNode result = new HuffmanNode("-", x.getCount() + y.getCount(), null, x, y);

and merge them, forming a tree with the sum of weights as weight - so far, so good.

    if(root == null){     // never happens, but doesn't matter
        root = result;
    }
    else{
        root.buildTree(result);

Then you insert the new-formed tree into the root,

    }
    huffmanList.add(result);                    
}

and add it back into the queue.

Now, let us consider a queue starting with

(a,1), (b,2), (c,3), (d,3), (e,3), ...

root = new HuffmanNode(); set root to (null, 0).

First, the a and b nodes are merged, giving <(a,1) | (-,3) | (b,2)>. Inserting into root produces

         (null,0)
          /    \
        null  (-,3)
              /   \
            (a,1) (b,2)

since 3 > 0. The queue is

<(a,1) | (-,3) | (b,2)>, (c,3), (d,3), (e,3) ...

after inserting the merged tree [the merged tree could also be inserted after a couple of weight-3 nodes, then it would take a bit longer].

Now the two lightest trees are popped and merged, giving

<AB | (-,6) | (c,3)>

(with the abbreviation AB = <(a,1) | (-,3) | (b,2)>). That tree is then inserted into the root tree. 6 > 0, so it's inserted into the right child of root, 6 > 3, so it's inserted into the right child of (-,3), 6 > 2, so it becomes the right child of the (b,2) node. But, the left child of the newly merged tree and the right child of root refer to the same object, so after this insertion, you have

                   __________
                  |          |
                  v          |
    (null,0)   (-,6)         |
    /      \   /   \         |
  null     (-,3)   (c,3)     |
           /   \             |
       (a,1)   (b,2)         |
                   \_________|

a cycle in what's supposed to be a tree. Next, the two nodes (d,3) and (e,3) are popped and merged, giving a tree of weight 6, and when that tree shall be inserted into the root graph, it would loop.

Different insertion behaviour and/or different weights of the letters would change the details, but the fact that after root.buildTree(result); and huffmanList.add(result); the queue contains a reference into the graph topped by root leads to cycles whenever you have enough nodes initially. And once you have enough cycles, the probability that a buildTree() call will not land in an infinite loop is small.

You simply should not call root.buildTree(result). The tree is constructed by simply merging the two lightest from the queue and reinserting the result, until the queue contains only one tree.

while(huffmanList.size() > 1){
    HuffmanNode x = huffmanList.poll();
    HuffmanNode y = huffmanList.poll();
    HuffmanNode result = new HuffmanNode("-", x.getCount() + y.getCount(), null, x, y);
    huffmanList.add(result);                    
}
root = huffmanList.poll();
like image 51
Daniel Fischer Avatar answered Oct 17 '22 00:10

Daniel Fischer