2012-12-07 30 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看到我的更新,並嘗試使用調試器。 –