Кодировка дерева Хаффмана - PullRequest
2 голосов
/ 22 июля 2010

У моего дерева Хаффмана, о котором я спрашивал ранее, есть еще одна проблема!Вот код:

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, идущее вправо, если оно больше, или влево, если оно меньше.

Но поскольку узлы не используют двойные числа типа int и т. Д., А используют только объекты, содержащие символы в виде строк или ноль, для обозначения не листа, а только корня.Другой вариант - сделать пробежку по порядку, чтобы найти лист, который я ищу, и в то же время, как я могу определить, много раз я ушел вправо или столько раз ушел, чтобы получить персонажа.

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.

Что меня смущает, так это то, что вы не можете определить гдевсе потому, что дерево явно не сбалансировано, и нет никакого определения, находится ли персонаж справа или слева от того места, где вы находитесь.Таким образом, вы должны искать по всему дереву, но если вы доберетесь до узла, который не является тем, что вы ищете, вы должны вернуться к другому корню, чтобы добраться до других листьев.

Ответы [ 5 ]

1 голос
/ 22 июля 2010

Пройдите через узлы дерева Хаффмана, чтобы получить карту типа {'a': "1001", 'b': "10001"} и т. Д. Вы можете использовать эту карту, чтобы получить двоичный код для конкретного символа.

Если вам нужно сделать наоборот, просто воспринимайте это как конечный автомат:

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

Честно говоря, я не изучал ваш код.Должно быть совершенно очевидно, что делать с причудливым деревом.

1 голос
/ 22 июля 2010

Помните, что если у вас есть 1001, у вас никогда не будет 10010 или 10011. Поэтому ваш базовый метод выглядит следующим образом (в псевдокоде):

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

Я не читал вашу программу, чтобы понять, как ее интегрировать, но в двух словах это ключевой элемент кодирования Хаффмана

Попробуйте что-то вроде этого - вы пытаетесь найти токен. Поэтому, если вы хотите найти строку для «10010», вам нужно выполнить поиск (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);

}
0 голосов
/ 14 января 2012
0 голосов
/ 12 января 2012

Полагаю, ваша домашняя работа уже сделана или уже слишком поздно, но, возможно, это поможет кому-то еще.

На самом деле все довольно просто.Вы создаете дерево, где 0 идет вправо, а 1 - влево.Чтение потока проведет вас по дереву.Когда вы нажимаете на лист, вы нашли письмо и начинаете все сначала.Как сказал Световой кодер, у вас никогда не будет буквы на листе без листьев.Дерево также охватывает все возможные последовательности битов.Поэтому навигация таким образом всегда работает независимо от кодированного ввода.

У меня было задание написать кодировщик / декодер Хаффмана, как вы недавно, и я написал сообщение в блоге с кодом на Java и болееобъяснение: http://www.byteauthor.com/2010/09/huffman-coding-in-java/

PS.Большая часть объяснения заключается в сериализации дерева Хаффмана с наименьшим возможным количеством битов, но алгоритмы кодирования / декодирования довольно просты в источниках.

0 голосов
/ 11 декабря 2011

Я рассмотрел два варианта, когда у меня была возможность попробовать дерево кодирования кодирования Хаффмана.

вариант 1: использовать указатель на основе двоичного дерева. Я кодировал большую часть этого, а затем почувствовал, что, чтобы отследить дерево от листа и найти кодировку, мне нужны родительские указатели. в противном случае, как упоминалось в этом посте, вы выполняете поиск по дереву, который не является решением для поиска кодировки сразу. Недостаток дерева, основанного на указателях, состоит в том, что для каждого узла в дереве мне нужно иметь 3 указателя, которые, по моему мнению, слишком много. Код для следования указателям прост, но сложнее, чем в варианте 2.

вариант 2: использовать дерево на основе массива для представления дерева кодирования, которое вы будете использовать во время выполнения для кодирования и декодирования. так что если вы хотите кодировку символа, вы найдете символ в массиве. Довольно прямолинейно, я использую стол, так что чмокаю, и там я получаю лист теперь я прослеживаю до корня, который находится в индексе 1 в массиве. Я делаю (current_index / 2) для родителя. если дочерний индекс равен parent / 2, это левый, а в противном случае правый.

вариант 2 был довольно легко закодировать, и хотя в массиве могут быть пустые места. Я думал, что это было лучше по производительности, чем дерево на основе указателей. Кроме того, идентификация корня и листа теперь является вопросом индексов, а не типа объекта. ;) Это также будет очень полезно, если вам нужно отправить свое дерево !?

также вы не выполняете поиск (root, 10110) при декодировании кода Хаффмана. Вы просто проходите дерево через поток закодированного потока битов, берете налево или направо в зависимости от вашего бита, и когда вы достигаете листа, вы выводите символ.

Надеюсь, это было полезно.

Харисанкар Кришна Свами ( пример )

...