2

以前質問したハフマン木には別の問題があります。コードは次のとおりです。

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

}

ここで行う必要があるのは、ツリーを検索して特定の文字のバイナリ コード (011001 など) を見つけるメソッドを作成する必要があることです。これを行う最善の方法は何ですか?AVLツリーが大きい場合は右に、小さい場合は左に行くように、ツリーを通常の検索を行うのではないかと思いました。

ただし、ノードはints doubleなどを使用せず、文字列またはnullとして文字を含むオブジェクトのみを使用して、リーフではなくルートのみを示すためです。もう1つのオプションは、探している葉を見つけるために順番通りに実行することですが、同時に、文字を取得するために何度も右に行ったのか、何度も左に行ったのかをどのように判断するのでしょうか.

package huffman;

public class Frequency implements Comparable  {
    private String s;
    private int n;
    public Frequency left;
    public Frequency right;

    Frequency(String s, int n)
    {
        this.s = s;
        this.n = n;
    }
    public String getString()
    {
        return s;
    }
    public int getFreq()
    {
        return n;
    }
    public void setFreq(int n)
    {
        this.n = n;
    }
    @Override
    public int compareTo(Object arg0) {
        Frequency other = (Frequency)arg0;

        return n < other.n ? -1 : (n == other.n ? 0 : 1);
    }
}

私がやろうとしているのは、実際に各文字に到達するためのバイナリ コードを見つけることです。したがって、エンコードしようとしている場合aabbbcccc、左に行くと 0、右に行くと 1 のバイナリ コードを保持する文字列を作成する方法を教えてください。

私が混乱しているのは、ツリーが明らかにバランスが取れておらず、キャラクターが自分のいる場所の右か左かを判断できないため、何かがどこにあるかを判断できないためです. したがって、ツリー全体を検索する必要がありますが、探しているものではないノードに到達した場合は、別のルートに戻って他のリーフに到達する必要があります。

4

5 に答える 5

1

ハフマンツリーノードをトラバースして、{'a': "1001"、'b': "10001"}などのマップを取得します。このマップを使用して、特定の文字のバイナリコードを取得できます。

逆にする必要がある場合は、ステートマシンとして処理してください。

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

正直言って、私はあなたのコードを調べませんでした。派手な木をどうするかはかなり明白なはずです。

于 2010-07-22T17:25:46.143 に答える
1

1001 がある場合、10010 または 10011 は決してないことを覚えておいてください。したがって、基本的なメソッドは次のようになります (疑似コード)。

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

プログラムを統合する方法を理解するためにあなたのプログラムを読みませんでしたが、それは一言で言えばハフマンエンコーディングの重要な要素です

このようなことを試してください - あなたはトークンを見つけようとしています。したがって、「10010」の文字列を見つけたい場合は、search(root,"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);

}
于 2010-07-22T17:13:35.297 に答える
0

これがScalaの実装です:http://blog.flotsam.nl/2011/10/huffman-coding-done-in-scala.html

于 2012-01-14T16:40:58.767 に答える
0

ハフマン符号化エンコーディングツリーを試してみたときに、2つのオプションを検討しました。

オプション1:ポインタベースの二分木を使用します。私はこれのほとんどをコーディングしてから、リーフからツリーをトレースしてエンコーディングを見つけるには、親ポインターが必要だと感じました。そうでなければ、この投稿で述べたように、あなたはすぐにエンコーディングを見つけるための解決策ではないツリーの検索を行います。ポインタベースのツリーの欠点は、ツリー内のノードごとに3つのポインタが必要であるということです。ポインタをたどるコードは単純ですが、オプション2よりも複雑です。

オプション2:配列ベースのツリーを使用して、実行時にエンコードおよびデコードに使用するエンコードツリーを表します。したがって、文字のエンコードが必要な場合は、配列内でその文字を見つけます。非常に簡単です。私はテーブルを使用しているので、すぐに葉を手に入れます。ここで、配列のインデックス1にあるルートまでトレースします。親に対して(current_index / 2)を実行します。子インデックスが親/2の場合は左、それ以外の場合は右です。

オプション2のコーディングは非常に簡単でしたが、配列には空のスペースを含めることができます。ポインタベースのツリーよりもパフォーマンスが優れていると思いました。ルートとリーフを識別することに加えて、オブジェクトタイプではなくインデックスの問題になりました。;)これは、ツリーを送信する必要がある場合にも非常に役立ちます!?

また、ハフマンコードをデコードしている間は、検索(root、10110)を行わないでください。エンコードされたビットストリームのストリームをツリーでたどり、ビットに基づいて左または右に進み、リーフに到達すると文字を出力します。

これがお役に立てば幸いです。

Harisankar Krishna Swamy(

于 2011-12-11T05:37:36.293 に答える
0

あなたの宿題はすでに終わっているか、かなり遅れていると思いますが、これは他の人の助けになるかもしれません。

それは実際には非常に簡単です。0 が右に、1 が左に行くツリーを作成します。ストリームを読むと、ツリーをナビゲートします。葉に当たると文字が見つかり、最初からやり直します。グローコーダーが言ったように、葉以外のノードには文字がありません。ツリーは、考えられるすべてのビット シーケンスもカバーします。したがって、この方法でのナビゲートは、エンコードされた入力に関係なく常に機能します。

少し前にあなたと同じようにハフマン エンコーダー/デコーダーを作成する割り当てがあり、Java のコードとより長い説明を含むブログ投稿を書きました: http://www.byteauthor.com/2010/09/huffman-coding -インジャバ/

PS。説明のほとんどは、可能な限り少ないビット数でハフマン ツリーをシリアル化することに関するものですが、ソース内のエンコード/デコード アルゴリズムは非常に単純です。

于 2012-01-11T22:22:49.070 に答える