java - 用Java实现LZ78算法

标签 java encoding dictionary decoding

我必须实现LZ78的编码器和解码器来压缩.txt,然后解压缩.txt

为此,我已经制作了编码器,文本输出的编码如下:

Text: "I have to improve my english"
Coded: "0I0 0h0a0v0e2t0o2i0m0p0r..."

LZ78 使用字典,字符串中的数字表示长字典条目的索引,如果该字母不在字典中,则为 0。

问题是:如果文本字符串是数字链,如何区分索引的数字和文本字符串的数字?

Text: "56786263...1234" <- the last entry can be ((index 12 concat'3')concat index 4) instead of (index 123 concat '4')
Coded: "050607082223...'randomnumber'4"
Dictionary: (List<String>)
...
123: 'randomnumber' <- this is saved as a string
...

如果字典的条目不超过 9 个,就没有问题。 我不能使用分隔符,因为这会在编码文本中添加大量数据。 我必须使用 bufferedReader 从编码文本中获取数据。 如果有不清楚的地方,我会提供一些额外的信息。

    BufferedReader bufR = new BufferedReader(new FileReader(codedText));
    BufferedWriter bufW = new BufferedWriter(new FileWriter(decodedText));

    List<Character> list = new ArrayList<Character>();
    int i=0;
    int aux=bufR.read();
    while(aux!=-1) {
        list.add((char)aux);
        i++;
        aux=bufR.read();
    }

    System.out.println(list);

这样,我就在“列表”中列出了用其他方法压缩的字符序列。 但问题是,如果字母是数字,没有任何类型的可写分隔符,如何对“数字/字母”对进行分组。

添加完整代码

    public class LZ78 {

List<String> diccionario;

public LZ78() {
    diccionario = new ArrayList<String>();
    diccionario.add(null);
}



public List<Character> codificar(List<Integer> listaNumeros){
    String codif="";
    List<Character> listaC =new ArrayList<Character>();
    String letra="";
    boolean brea=false;
    int posicion=0;
    for(int i=0;i<=listaNumeros.size()+1;i++){
        int num=listaNumeros.get(i);
        letra+=(char)num;

        if(!diccionario.contains(letra)){   
            diccionario.add(letra);
            codif+=0;
            listaC.add('0');
            codif+=letra;
            char paso=letra.charAt(0);
            listaC.add(paso);
            letra="";

        }else{

            while(diccionario.contains(letra)){

                i++;

                if(i>=listaNumeros.size()){

                    brea=true;


                    if(!diccionario.contains(letra)){
                    listaC.add('0');
                    char paso2=letra.charAt(0);
                    listaC.add(paso2);
                    }else{
                        int index=diccionario.indexOf(letra);
                        String paso3=""+index;
                        for (int j = 0; j < paso3.length(); j++) {
                            listaC.add(paso3.charAt(j));
                        }

                    }
                    System.out.println("BREAK!");
                    break;
                }
                posicion=diccionario.indexOf(letra);
                num=listaNumeros.get(i);
                letra+=(char)num;


            }

            if(brea){
                break;
            }

            i++;

            diccionario.add(letra);
            letra=""+letra.charAt(letra.length()-1);    
            codif+=posicion;

            String numero=""+posicion;
            for (int j = 0; j < numero.length(); j++) {
                listaC.add(numero.charAt(j));
            }


            codif+=letra;   
            char paso=letra.charAt(0);
            listaC.add(paso);

            letra="";
            i--;

        }
    }

    System.out.println(codif);

    return listaC;
}



//public void decodificar(List<Integer>)


public void codificacion(File textoPlano, File textoPlanoCodificado)
        throws IOException {
    BufferedReader bufLectura = new BufferedReader(new FileReader(
            textoPlano));
    BufferedWriter bufEscritura = new BufferedWriter(new FileWriter(
            textoPlanoCodificado));

    List<Integer> list = new ArrayList<Integer>();
    int i=0;
    int cosa=bufLectura.read();
    while(cosa!=-1) {
        list.add(cosa);
        i++;
        cosa=bufLectura.read();
    }

    List<Character> code=codificar(list);

    char[] codigo=new char[code.size()];

    for (int j = 0; j < code.size(); j++) {
        //System.out.print(j+":'"+code.get(j)+"'   ");
        codigo[j]=code.get(j);

        bufEscritura.write(codigo[j]);
    }


    System.out.println("FIN codificacion");


    bufEscritura.close();

}

public void decodificacion(File textoC, File textoD) throws IOException{
    BufferedReader bufLectura = new BufferedReader(new FileReader(textoC));
    BufferedWriter bufEscritura = new BufferedWriter(new FileWriter(textoD));

    List<Character> list = new ArrayList<Character>();
    int i=0;
    int cosa=bufLectura.read();
    while(cosa!=-1) {
        list.add((char)cosa);
        i++;
        cosa=bufLectura.read();
    }

    System.out.println(list);

    //List<Integer> list2 =decodificar(list);
    /*
    List<Character> code=codificar(list);

    char[] codigo=new char[code.size()];
    for (int j = 0; j < code.size()-1; j++) {
        codigo[j]=code.get(j);

        bufEscritura.write(codigo[j]);
    }
    System.out.println("FIN codificacion");


    bufEscritura.close();
    */
}

public static void main(String[] args) throws IOException {
    LZ78 lz78 = new LZ78();
    File textoPlano, textoPlanoCodificado, textoPlanoDecodificado;

    textoPlano = new File("C:/pruebas/T.txt");
    textoPlanoCodificado = new File("C:/pruebas/TOut.txt");
    textoPlanoDecodificado = new File("C:/pruebas/TDecOut.txt");
    lz78.codificacion(textoPlano, textoPlanoCodificado);
    lz78.decodificacion(textoPlanoCodificado, textoPlanoDecodificado);

    /*
     * textoPlano = new File("C:/pruebas/MobyDick.txt");
     * textoPlanoCodificado = new File("C:/pruebas/MobyDickOut.txt");
     * textoPlanoDecodificado = new File("C:/pruebas/MobyDickDecOut.txt");
     * lz78.codificacion(textoPlano, textoPlanoCodificado);
     * lz78.decodificacion(textoPlanoCodificado, textoPlanoDecodificado);
     * 
     * textoPlano = new File("C:/pruebas/Quixote.txt"); textoPlanoCodificado
     * = new File("C:/pruebas/QuixoteOut.txt"); textoPlanoDecodificado = new
     * File("C:/pruebas/QuixoteDecOut.txt"); lz78.codificacion(textoPlano,
     * textoPlanoCodificado); lz78.decodificacion(textoPlanoCodificado,
     * textoPlanoDecodificado);
     */
}

}

最佳答案

注意:我假设这是家庭作业。如果不是,那么您应该对位(而不是字符)进行操作并实现 LZW而不是LZ78

字典索引的长度取决于字典的总大小。虽然只有 9 个条目,但您只能使用 1 个字符。一旦字典中有 10 个条目,您就需要使用 2 个字符作为所有条目的索引。

请注意,解码器在处理流时会知道它看到了多少个字典条目,因此您不需要单独存储字典的大小,只需逐渐增加用于存储索引的字符数即可。 即一旦您存储了第 10 个字典条目,您就开始为所有 future 索引使用 2 个字符。在输入第 100 个字典条目后,您将使用 3 个字符,依此类推。

编辑:This link有一个逐步示例,显示在解码阶段重建字典。尽管该链接描述了 LZW (不是 LZ78),但其想法是相同的:您需要在解码时重建整个字典,并且不能重用编码步骤中的字典(例如,考虑解码器和编码器可能位于不同计算机上的情况-> 字典通过网络发送。)

关于java - 用Java实现LZ78算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20443035/

相关文章:

java - Windows 与 Java 中 Unix 的文件路径问题

Java Sound : devices found when run in IntelliJ, 但不在 SBT 中

java - 想要在 2 个不同的 jdk 中构建 2 个应用程序,然后在 2 个 Tomcat 服务器中运行

c# - 如何设置 System.Net.Mail.MailMessage 的附件文件编码?

java - 在没有单击按钮的情况下输入后,将 EditText 的值添加到 strings.xml 中的字符串

python - 具有混合编码的文件 - Python

php - Javascript 和 PHP 中的字符编码是否不同?

r - 在 R 中的状态 map 上绘制条形图

java - 按值对映射进行排序

javascript - 未定义的属性 'map' (JavaScript)