2010-07-22 10 views
2

Mon arbre Huffman que j'avais demandé plus tôt a un autre problème! Voici le code:Huffman Tree Encodage

package huffman; 

import java.io.FileNotFoundException; 
import java.io.FileReader; 
import java.util.ArrayList; 
import java.util.PriorityQueue; 
import java.util.Scanner; 

public class Huffman { 

    public ArrayList<Frequency> fileReader(String file) 
    { 
     ArrayList<Frequency> al = new ArrayList<Frequency>(); 
     Scanner s; 
     try { 

      s = new Scanner(new FileReader(file)).useDelimiter(""); 
      while (s.hasNext()) 
      { 
       boolean found = false; 
       int i = 0; 
       String temp = s.next(); 
       while(!found) 
       { 


        if(al.size() == i && !found) 
        { 
         found = true; 
         al.add(new Frequency(temp, 1)); 
        } 
        else if(temp.equals(al.get(i).getString())) 
        { 
         int tempNum = al.get(i).getFreq() + 1; 
         al.get(i).setFreq(tempNum); 
         found = true; 
        } 
        i++; 

       } 



      } 
     } catch (FileNotFoundException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     return al; 
    } 
    public Frequency buildTree(ArrayList<Frequency> al) 
    { 
     Frequency r = al.get(1); 
     PriorityQueue<Frequency> pq = new PriorityQueue<Frequency>(); 
     for(int i = 0; i < al.size(); i++) 
     { 
      pq.add(al.get(i));   
     } 
     /*while(pq.size() > 0) 
     { 
      System.out.println(pq.remove().getString()); 
     }*/ 

     for(int i = 0; i < al.size() - 1; i++) 
     { 
      Frequency p = pq.remove(); 
      Frequency q = pq.remove(); 
      int temp = p.getFreq() + q.getFreq(); 
      r = new Frequency(null, temp); 
      r.left = p; 
      r.right = q; 
      pq.add(r); // put in the correct place in the priority queue 
     } 
     pq.remove(); // leave the priority queue empty 
     return(r); // this is the root of the tree built 

    } 

    public void inOrder(Frequency top) 
    { 
     if(top == null) 
     { 
      return; 
     } 
     else 
     { 
      inOrder(top.left); 
      System.out.print(top.getString() +", "); 
      inOrder(top.right); 
      return; 
     } 
    } 
    public void printFreq(ArrayList<Frequency> al) 
    { 
     for(int i = 0; i < al.size(); i++) 
     { 
      System.out.println(al.get(i).getString() + "; " + al.get(i).getFreq()); 
     } 
    } 

} 

Ce qui doit être fait est maintenant je dois créer une méthode qui recherche dans l'arborescence pour trouver le code binaire (011001, etc.) au caractère spécifique. Quelle est la meilleure façon de procéder? Je pensais que je ferais peut-être une recherche normale à travers l'arbre comme si c'était un arbre AVL allant vers la droite s'il était plus grand ou à gauche s'il était plus petit.

Mais parce que les nœuds n'utilisent pas ints doubles etc. mais seulement en utilisant des objets qui contiennent des caractères comme des chaînes ou null pour signifier que ce n'est pas une feuille mais seulement une racine. L'autre option serait de faire une recherche en cours pour trouver la feuille que je cherche, mais en même temps, comment pourrais-je déterminer si je suis allé droit autant de fois ou à gauche tant de fois pour obtenir le personnage. Ce que j'essaie de faire est de trouver le code binaire pour arriver à chaque caractère. C'est ce que j'essaie de faire. Donc, si j'essayais de coder aabbbcccc comment je créer une chaîne contenant le code binaire pour un aller à gauche est 0 et aller à droite est 1.

Ce qui m'a confondu est parce que vous ne pouvez pas déterminer où est quelque chose parce que le l'arbre est évidemment déséquilibré et il n'y a pas de déterminant si un personnage est à droite ou à gauche de l'endroit où vous êtes. Vous devez donc effectuer une recherche dans l'ensemble de l'arborescence, mais si vous arrivez à un nœud qui n'est pas ce que vous recherchez, vous devez revenir à une autre racine pour accéder aux autres feuilles.

Répondre

1

Rappelez-vous, si vous avez 1001, vous ne serez jamais un 10010 ou 10011. Ainsi, votre méthode de base ressemble à ceci (en pseudocode):

if(input == thisNode.key) return thisNode.value 
if(input.endsWith(1)) return search(thisNode.left) 
else return search(thisNode.right) 

Je ne l'ai pas lu votre programme pour savoir comment pour l'intégrer, mais c'est un élément clé de l'encodage de huffman en un mot

Essayez quelque chose comme ceci - vous essayez de trouver un jeton. Donc, si vous voulez trouver la chaîne pour « 10010 », vous feriez recherche (racine, « 10010 »)

String search(Frequency top, String token) { 
    return search(top,token,0); 
} 

// depending on your tree, you may have to switch top.left and top.right 
String search(Frequency top, String token, int depth) { 
    if(token.length() == depth) return "NOT FOUND"; 
    if(token.length() == depth - 1) return top.getString(); 
    if(token.charAt(depth) == '0') return search(top.left,token,depth+1); 
    else return search(top.right,token,depth+1); 

} 
+0

si l'im objet à l'aide devrait avoir une clé contenant le code binaire pour elle? donc je peux juste accéder directement à partir de l'objet que je cherche? – Zieklecknerizer

+0

Attendez une seconde, je vais jeter un coup d'oeil à votre programme et voir si je peux offrir un aperçu. Cela ressemble étrangement à des devoirs - si c'est vous devriez ajouter l'étiquette de devoir. :) – corsiKa

+0

ouais c'est HW suppose que je devrais alors haha ​​ – Zieklecknerizer

1

Traverse à travers les nœuds d'arbre de Huffman pour obtenir une carte comme { « a »: « 1001 ", 'b':" 10001 "} etc. Vous pouvez utiliser cette carte pour obtenir le code binaire d'un caractère spécifique.

Si vous devez faire en sens inverse, juste traiter comme une machine d'état:

state = huffman_root 
for each bit 
    if (state.type == 'leaf') 
     output(state.data); 
     state = huffman_root 
    state = state.leaves[bit] 

dit Honnêtement, je n'ai pas regardé dans votre code. Il devrait être assez évident quoi faire avec l'arbre de fantaisie.

+0

Dans un arbre de Huffman, les noeuds non-feuille peuvent avoir des données. – corsiKa

+0

Cela semble amusant. Mais quel est le point d'avoir des données dans les nœuds non-feuille? – Cheery

0

J'ai envisagé deux options lorsque j'essayais de coder Huffman.

option 1: utiliser un arbre binaire basé sur un pointeur. J'ai codé la plupart de ceci et ai alors senti que, pour tracer l'arbre de la feuille pour trouver un codage, j'avais besoin de pointeurs de parent. D'autre part, comme mentionné dans ce post, vous faites une recherche de l'arbre qui n'est pas une solution pour trouver l'encodage tout de suite. L'inconvénient de l'arbre basé sur un pointeur est que, je dois avoir 3 pointeurs pour chaque nœud dans l'arbre que je pensais être trop. Le code pour suivre les pointeurs est simple mais plus compliqué que dans l'option 2.

option 2: utiliser un arbre basé sur un tableau pour représenter l'arbre de codage que vous utiliserez dans l'exécution pour encoder et décoder.donc si vous voulez l'encodage d'un caractère, vous trouvez le caractère dans le tableau. Assez simple, j'utilise une table si bien droite et là je reçois la feuille. maintenant je trace jusqu'à la racine qui est à l'index 1 dans le tableau. Je fais un (current_index/2) pour le parent. Si l'index enfant est parent/2, il est à gauche et à droite.

L'option 2 était assez facile à coder et bien que le tableau puisse avoir des espaces vides. Je pensais que c'était mieux en performance qu'un arbre basé sur un pointeur. En plus d'identifier la racine et la feuille est maintenant une question d'indices plutôt que le type d'objet. ;) Cela sera également très utile si vous devez envoyer votre arbre !?

également, vous ne recherchez pas (root, 10110) lors du décodage du code Huffman. Vous marchez simplement l'arbre à travers le flux de bitstream encodé, prenez à gauche ou à droite en fonction de votre bit et quand vous atteignez la feuille, vous produisez le caractère.

J'espère que cela vous a été utile.

Harisankar Krishna Swamy (example)

0

Je suppose que vos devoirs est soit fait ou très tard maintenant, mais peut-être cela va aider quelqu'un d'autre.

C'est en fait assez simple. Vous créez un arbre où 0 va à droite et 1 va à gauche. La lecture du flux vous guidera à travers l'arbre. Quand vous frappez une feuille, vous trouvez une lettre et recommencez depuis le début. Comme l'a dit Glowcoder, vous n'aurez jamais de lettre sur un nœud non-feuille. L'arbre couvre également toutes les séquences de bits possibles. La navigation de cette manière fonctionne toujours quelle que soit l'entrée encodée.

J'ai eu une mission d'écrire un codeur huffman/décodeur comme vous il y a un certain temps et j'ai écrit un billet de blog avec le code en Java et une explication plus: http://www.byteauthor.com/2010/09/huffman-coding-in-java/

PS. La plupart des explications portent sur la sérialisation de l'arbre de Huffman avec le moins de bits possibles, mais les algorithmes de codage/décodage sont assez simples dans les sources.