2012-12-07 24 views
6

我正在编写一个Huffman编码程序,我几乎完成了,但我陷入了一个无限递归循环。有没有人有一个想法,这是错误的?huffman树中的无限递归,StackOverError

这是我收到的错误:

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) 

,输出是连续5:1,5:4,5:2,重复

我的数据文件看起来是这样的:

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 

和我的代码是

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(" "); 
} 
} 

回答

3

你的树构建有过错。

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){  // never happens, but doesn't matter 
     root = result; 
    } 
    else{ 
     root.buildTree(result); 

然后你插入新形成的树到root

} 
    huffmanList.add(result);      
} 

,并将其添加回到队列中。

现在,让我们考虑一个队列开始

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

root = new HuffmanNode();设置root(null, 0)

首先,将ab节点合并,给出<(a,1) | (-,3) | (b,2)>。插入root产生

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

3 > 0。队列是

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

插入合并树后[所述合并树也可以几个重3节点的插入后,那么这将需要更长的时间。

现在两个最轻的树木被弹出和合并,给

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

(与缩写AB = <(a,1) | (-,3) | (b,2)>)。然后将该树插入root树中。所以它被插入到root,6 > 3的右边孩子中,所以它被插入(-,3)6 > 2的右边孩子,因此它成为(b,2)节点的右边孩子。不过,合并后的新树的左子和root右子指的是同一个对象,所以这个插入之后,你有

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

在什么应该是一棵树一个周期。接下来,弹出并合并两个节点(d,3)(e,3),给出权重为6的树,并且当该树应插入到root图中时,它将循环。

不同的插入行为和/或字母会改变细节的不同的权重,但root.buildTree(result);huffmanList.add(result);后的队列包含引用到由root高居图的事实导致的周期,只要你有足够的节点开始。一旦你有足够的周期,一个buildTree()呼叫不会在无限循环中降落的概率很小。您可以拨打root.buildTree(result)。通过简单地合并队列中最亮的两个并重新插入结果来构造树,直到队列仅包含一棵树。

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(); 
+0

丹。一个真正壮观和直观的答案。我非常感谢您花时间以这种勤奋的方式诊断代码。非常感谢。 – user1093111

+0

一切正常。惊人的。 – user1093111

0

尝试改变

if(root.equals("null")){ 

if(root == null){ 

而且

尽量缩短你的numerious if这样的代码

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

我得到相同的错误 – user1093111

+1

@ user1093111,好的,你必须改变它。比较引用和String是绝对没有意义的。 –

+0

@ user1093111看到我的更新,并尝试使用调试器。 –