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(" ");
}
}
Your tree-building is at fault.
You take the two lightest trees from the queue,
and merge them, forming a tree with the sum of weights as weight – so far, so good.
Then you insert the new-formed tree into the
root,and add it back into the queue.
Now, let us consider a queue starting with
root = new HuffmanNode();setrootto(null, 0).First, the
aandbnodes are merged, giving<(a,1) | (-,3) | (b,2)>. Inserting intorootproducessince
3 > 0. The queue isafter 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
(with the abbreviation
AB = <(a,1) | (-,3) | (b,2)>). That tree is then inserted into theroottree.6 > 0, so it’s inserted into the right child ofroot,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 ofrootrefer to the same object, so after this insertion, you havea 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 therootgraph, 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);andhuffmanList.add(result);the queue contains a reference into the graph topped byrootleads to cycles whenever you have enough nodes initially. And once you have enough cycles, the probability that abuildTree()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.