Mkpakọ data site na iji Huffman algọridim

entry

N'isiokwu a, m ga-ekwu maka Huffman algorithm a ma ama, yana ngwa ya na mkpakọ data.

N'ihi ya, anyị ga-ede ihe ndekọ dị mfe. Atụlelarị nke a akụkọ na Habré, ma na-enweghị mmejuputa atumatu. The theoretical material of the current post na-esite na nkuzi sayensị kọmputa ụlọ akwụkwọ na akwụkwọ Robert Laforet "Data Structures and Algorithms in Java". Ya mere, a na-egbutu ihe niile!

Echiche ole na ole

N'ime faịlụ ederede oge niile, a na-etinye koodu otu mkpụrụedemede na ibe 8 (ASCII ngbanwe) ma ọ bụ 16 (Unicode koodu). Ọzọ, anyị ga-atụle ngbanwe ASCII. Dịka ọmụmaatụ, were ahịrị s1 = "SUSIE KWURU Ọ dị mfe". Enwere ngụkọta nke mkpụrụedemede 22 n'ahịrị, n'ụzọ nkịtị, gụnyere oghere na agwa ahịrị ọhụrụ - 'n'. Faịlụ nwere ahịrị a ga-atụ 22*8 = 176 bits. Ajụjụ na-ebilite ozugbo: ọ bụ ihe ezi uche dị na ya iji ibe 8 niile tinye koodu 1 agwa? Anyị anaghị eji mkpụrụedemede ASCII niile. Ọbụlagodi na ha mere ya, ọ ga-abụ ihe ezi uche dị na ya maka mkpụrụedemede a na-ahụkarị - S - ka e nye ya koodu kacha nso, yana maka mkpụrụedemede obere - T (ma ọ bụ U, ma ọ bụ 'n') - ka enye ya koodu ogologo. Nke a bụ ihe Huffman algọridim mejupụtara: ọ dị mkpa ịchọta nhọrọ ntinye koodu kacha mma nke faịlụ ahụ ga-enwe oke kacha nta. Ọ bụ ihe nkịtị na ogologo koodu ga-adị iche maka akara dị iche iche - nke a bụ ihe algorithm dabere na ya.

Ndokwa

Kedu ihe kpatara na ị nyeghị agwa 'S' koodu, dịka ọmụmaatụ, 1 bit ogologo: 0 ma ọ bụ 1. Ka ọ bụrụ 1. Mgbe ahụ agwa nke abụọ a na-ahụkarị - '' (ohere) - nye 0. Were ya na ị malitere decoding ozi gị - eriri s1 nke etinyere ya - wee hụ na koodu ahụ na-amalite na 1. Yabụ, kedu ihe ị na-eme: nke a bụ agwa S, ka ọ bụ ụdị agwa ọzọ, dịka ọmụmaatụ A? Ya mere, iwu dị mkpa na-ebilite:

Koodu ọ bụla ekwesịghị ịbụ prefix nke ọzọ

Iwu a bụ isi na algọridim. Ya mere, ịmepụta koodu na-amalite site na tebụl ugboro, nke na-egosi ugboro (ọnụọgụ ihe omume) nke akara ọ bụla:

Mkpakọ data site na iji Huffman algọridim Ekwesịrị itinye akara mkpụrụedemede ndị nwere ọtụtụ ihe na-eme kwere omume ọnụ ọgụgụ nke ibe n'ibe. M ga-enye ọmụmaatụ nke otu tebụl koodu enwere ike:

Mkpakọ data site na iji Huffman algọridim Ya mere, ozi edobere ga-adị ka nke a:

10 01111 10 110 1111 00 10 010 1110 10 00 110 0110 00 110 10 00 1111 010 10 1110 01110

Eji m oghere kewaa koodu agwa ọ bụla. Nke a agaghị eme na faịlụ abịakọrọ n'ezie!
Ajụjụ na-ebilite: kedu ka nwa okorobịa a si wepụta koodu iji mepụta tebụl koodu? A ga-atụle nke a n'okpuru.

Ịrụ osisi Huffman

Nke a bụ ebe osisi ọchụchọ ọnụọgụ abụọ na-abịa napụta. Echegbula onwe gị, ịgaghị achọ ọchụchọ, fanye ma ọ bụ hichapụ ụzọ ebe a. Nke a bụ nhazi osisi na java:

public class Node {
    private int frequence;
    private char letter;
    private Node leftChild;
    private Node rightChild;
    ...
}

class BinaryTree {
    private Node root;

    public BinaryTree() {
        root = new Node();
    }
    public BinaryTree(Node root) {
        this.root = root;
    }
    ...
}

Nke a abụghị koodu zuru oke, koodu zuru ezu ga-adị n'okpuru.

Nke a bụ algọridim maka iwu osisi:

  1. Mepụta ihe Node maka agwa ọ bụla site na ozi (akara s1). N'ọnọdụ anyị, a ga-enwe oghere 9 (Ihe Node). Ọnụ ọ bụla nwere mpaghara data abụọ: akara na ugboro ole
  2. Mepụta ihe osisi (BinaryTree) maka Node ọ bụla. Ọnụ na-aghọ mgbọrọgwụ osisi ahụ.
  3. Fanye osisi ndị a n'ahịrị dị mkpa. Na ala nke ugboro ole, ka ihe kacha mkpa. Ya mere, mgbe ị na-ewepụta, a na-ahọrọ dervo na ugboro kachasị dị ala.

Ọzọ, ị ga-eme ihe ndị a na cyclically:

  1. Wepu osisi abụọ site na kwụ n'ahịrị dị mkpa ma mee ka ha bụrụ ụmụ nke oghere ọhụrụ (ọnụ ọnụ nke emepụtara ọhụrụ na-enweghị akwụkwọ ozi). Ugboro nke oghere ọhụrụ ahụ hà nhata nke ugboro ugboro nke osisi abụọ ndị a na-erite.
  2. Maka ọnụ ọnụ a, mepụta osisi nwere mgbọrọgwụ na ọnụ a. Fanye osisi a azụ n'ahịrị mbụ. (Ebe ọ bụ na osisi ahụ nwere ugboro ọhụrụ, ọ ga-abụrịrị na ọ ga-apụta na ebe ọhụrụ na kwụ n'ahịrị)
  3. Gaa n'ihu nzọụkwụ 1 na 2 ruo mgbe enwere naanị otu osisi fọdụrụ na kwụ n'ahịrị - osisi Huffman

Tụlee algọridim a na ahịrị s1:

Mkpakọ data site na iji Huffman algọridim

N'ebe a akara "lf" (linefeed) pụtara ahịrị ọhụrụ, "sp" (ohere) bụ oghere.

Kedu ihe ọzọ?

Anyị nwere osisi Huffman. Ọ DỊ MMA. Gịnịkwa ka a ga-eji ya mee? Ha agaghị ewere ya n'efu ma mgbe ahụ, ị ​​ga-achọ ịchọta ụzọ niile nwere ike isi na mgbọrọgwụ ruo na epupụta nke osisi ahụ. Ka anyị kwenye igosi ihu 0 ma ọ bụrụ na ọ na-eduga na nwata aka ekpe na 1 ma ọ bụrụ na ọ na-eduga na nke ziri ezi. N'ikwu ya n'ụzọ ziri ezi, n'akwụkwọ akụkọ a, koodu nke akara bụ ụzọ sitere na mgbọrọgwụ osisi gaa n'akwụkwọ nke nwere akara a.

Mkpakọ data site na iji Huffman algọridim

Otu a ka tebụl koodu si pụta. Rịba ama na ọ bụrụ na anyị atụle tebụl a, anyị nwere ike ikwubi banyere "ịdị arọ" nke akara ọ bụla - nke a bụ ogologo koodu ya. Mgbe ahụ, n'ụdị mkpakọ, faịlụ mbụ ga-atụ: 2 * 3 + 2*4 + 3 * 3 + 6 * 2 + 1 * 4 + 1 * 5 + 2 * 4 + 4 * 2 + 1 * 5 = 65 bits . Na mbụ ọ tụrụ 176 bit. N'ihi ya, anyị belatara ya dị ka 176/65 = 2.7 ugboro! Ma nke a bụ utopia. O yighị ka ọ ga-enweta ọnụọgụgụ dị otú ahụ. Gịnị kpatara? A ga-atụle nke a obere oge ma emechaa.

Ịmepụta koodu

Ọfọn, ikekwe ihe kachasị mfe fọdụrụ bụ ngbanwe. Echere m na ọtụtụ n'ime unu echerela na anyị enweghị ike ịmepụta faịlụ abịakọrọ na-enweghị nkọwa ọ bụla gbasara otu esi etinye ya - anyị agaghị enwe ike ịmegharị ya! Ee, ee, ọ na-esiri m ike ịghọta nke a, mana m ga-emepụta table.txt ederede na tebụl mkpakọ:

01110
 00
A010
E1111
I110
S10
T0110
U01111
Y1110

Ntinye tebụl n'ụdị 'akara' 'koodu agwa'. Kedu ihe kpatara 01110 na-enweghị akara? N'ezie, ọ bụ na akara ngosi, ọ bụ naanị na ngwaọrụ java m na-eji mgbe m na-emepụta faịlụ, a na-atụgharị agwa ọhụrụ - 'n' ka ọ bụrụ akara ọhụrụ (n'agbanyeghị otú ọ nwere ike isi dị nzuzu). Ya mere, ahịrị efu dị n'elu bụ njirimara maka koodu 01110. Maka koodu 00, agwa bụ oghere na mmalite nke akara. M ga-ekwu ozugbo na maka ọnụọgụ Khan anyị, usoro a nke ịchekwa tebụl nwere ike ịsị na ọ bụ ihe na-enweghị isi. Mana ọ dị mfe nghọta na mejuputa ya. M ga-enwe obi ụtọ ịnụ ndụmọdụ gị na nkwupụta gbasara njikarịcha.

Inwe tebụl a na-eme ka ọ dị mfe imezi koodu. Ka anyị cheta iwu anyị gbasoro mgbe ị na-eke koodu:

Koodu ọ bụla ekwesịghị ịbụ prefix nke ọzọ

Nke a bụ ebe ọ na-arụ ọrụ nkwado. Anyị na-agụ usoro nke nta nke nta ma, ozugbo eriri d, nke mejupụtara ibe n'ibe agụ, dakọtara na ntinye koodu kwekọrọ na agwa agwa, anyị matara ozugbo na akara agwa (na naanị ya!). Na-esote, anyị na-edepụta agwa n'ime ahịrị ngbanwe (akara nwere ozi decoded), megharịa ahịrị d, wee gụọ faịlụ etinyere.

Mmejuputa iwu

Oge erugo iweda koodu m n'ala wee dee ebe nchekwa. Ka anyị kpọọ ya Compressor.

Malite ọzọ. Nke mbụ, anyị na-ede klas Node:

public class Node {
    private int frequence;//частота
    private char letter;//буква
    private Node leftChild;//левый потомок
    private Node rightChild;//правый потомок

   

    public Node(char letter, int frequence) { //собственно, конструктор
        this.letter = letter;
        this.frequence = frequence;
    }

    public Node() {}//перегрузка конструтора для безымянных узлов(см. выше в разделе о построении дерева Хаффмана)
    public void addChild(Node newNode) {//добавить потомка
        if (leftChild == null)//если левый пустой=> правый тоже=> добавляем в левый
            leftChild = newNode;
        else {
            if (leftChild.getFrequence() <= newNode.getFrequence()) //в общем, левым потомком
                rightChild = newNode;//станет тот, у кого меньше частота
            else {
                rightChild = leftChild;
                leftChild = newNode;
            }
        }

        frequence += newNode.getFrequence();//итоговая частота
    }

    public Node getLeftChild() {
        return leftChild;
    }

    public Node getRightChild() {
        return rightChild;
    }

    public int getFrequence() {
        return frequence;
    }

    public char getLetter() {
        return letter;
    }

    public boolean isLeaf() {//проверка на лист
        return leftChild == null && rightChild == null;
    }
}

Ugbu a osisi:

class BinaryTree {
    private Node root;

    public BinaryTree() {
        root = new Node();
    }

    public BinaryTree(Node root) {
        this.root = root;
    }

    public int getFrequence() {
        return root.getFrequence();
    }

    public Node getRoot() {
        return root;
    }
}

kwụ n'ahịrị ụzọ:

import java.util.ArrayList;//да-да, очередь будет на базе списка

class PriorityQueue {
    private ArrayList<BinaryTree> data;//список очереди
    private int nElems;//кол-во элементов в очереди

    public PriorityQueue() {
        data = new ArrayList<BinaryTree>();
        nElems = 0;
    }

    public void insert(BinaryTree newTree) {//вставка
        if (nElems == 0)
            data.add(newTree);
        else {
            for (int i = 0; i < nElems; i++) {
                if (data.get(i).getFrequence() > newTree.getFrequence()) {//если частота вставляемого дерева меньше 
                    data.add(i, newTree);//чем част. текущего, то cдвигаем все деревья на позициях справа на 1 ячейку                   
                    break;//затем ставим новое дерево на позицию текущего
                }
                if (i == nElems - 1) 
                    data.add(newTree);
            }
        }
        nElems++;//увеличиваем кол-во элементов на 1
    }

    public BinaryTree remove() {//удаление из очереди
        BinaryTree tmp = data.get(0);//копируем удаляемый элемент
        data.remove(0);//собственно, удаляем
        nElems--;//уменьшаем кол-во элементов на 1
        return tmp;//возвращаем удаленный элемент(элемент с наименьшей частотой)
    }
}

Klas nke na-emepụta osisi Huffman:

public class HuffmanTree {
    private final byte ENCODING_TABLE_SIZE = 127;//длина кодировочной таблицы
    private String myString;//сообщение
    private BinaryTree huffmanTree;//дерево Хаффмана
    private int[] freqArray;//частотная таблица
    private String[] encodingArray;//кодировочная таблица


    //----------------constructor----------------------
    public HuffmanTree(String newString) {
        myString = newString;

        freqArray = new int[ENCODING_TABLE_SIZE];
        fillFrequenceArray();

        huffmanTree = getHuffmanTree();

        encodingArray = new String[ENCODING_TABLE_SIZE];
        fillEncodingArray(huffmanTree.getRoot(), "", "");
    }

    //--------------------frequence array------------------------
    private void fillFrequenceArray() {
        for (int i = 0; i < myString.length(); i++) {
            freqArray[(int)myString.charAt(i)]++;
        }
    }

    public int[] getFrequenceArray() {
        return freqArray;
    }

    //------------------------huffman tree creation------------------
    private BinaryTree getHuffmanTree() {
        PriorityQueue pq = new PriorityQueue();
        //алгоритм описан выше
        for (int i = 0; i < ENCODING_TABLE_SIZE; i++) {
            if (freqArray[i] != 0) {//если символ существует в строке
                Node newNode = new Node((char) i, freqArray[i]);//то создать для него Node
                BinaryTree newTree = new BinaryTree(newNode);//а для Node создать BinaryTree
                pq.insert(newTree);//вставить в очередь
            }
        }

        while (true) {
            BinaryTree tree1 = pq.remove();//извлечь из очереди первое дерево.

            try {
                BinaryTree tree2 = pq.remove();//извлечь из очереди второе дерево

                Node newNode = new Node();//создать новый Node
                newNode.addChild(tree1.getRoot());//сделать его потомками два извлеченных дерева
                newNode.addChild(tree2.getRoot());

                pq.insert(new BinaryTree(newNode);
            } catch (IndexOutOfBoundsException e) {//осталось одно дерево в очереди
                return tree1;
            }
        }
    }

    public BinaryTree getTree() {
        return huffmanTree;
    }

    //-------------------encoding array------------------
    void fillEncodingArray(Node node, String codeBefore, String direction) {//заполнить кодировочную таблицу
        if (node.isLeaf()) {
            encodingArray[(int)node.getLetter()] = codeBefore + direction;
        } else {
            fillEncodingArray(node.getLeftChild(), codeBefore + direction, "0");
            fillEncodingArray(node.getRightChild(), codeBefore + direction, "1");
        }
    }

    String[] getEncodingArray() {
        return encodingArray;
    }

    public void displayEncodingArray() {//для отладки
        fillEncodingArray(huffmanTree.getRoot(), "", "");

        System.out.println("======================Encoding table====================");
        for (int i = 0; i < ENCODING_TABLE_SIZE; i++) {
            if (freqArray[i] != 0) {
                System.out.print((char)i + " ");
                System.out.println(encodingArray[i]);
            }
        }
        System.out.println("========================================================");
    }
    //-----------------------------------------------------
    String getOriginalString() {
        return myString;
    }
}

Klas nwere nke na-edekọ/decode:

public class HuffmanOperator {
    private final byte ENCODING_TABLE_SIZE = 127;//длина таблицы
    private HuffmanTree mainHuffmanTree;//дерево Хаффмана (используется только для сжатия)
    private String myString;//исходное сообщение
    private int[] freqArray;//частотаная таблица
    private String[] encodingArray;//кодировочная таблица
    private double ratio;//коэффициент сжатия 


    public HuffmanOperator(HuffmanTree MainHuffmanTree) {//for compress
        this.mainHuffmanTree = MainHuffmanTree;

        myString = mainHuffmanTree.getOriginalString();

        encodingArray = mainHuffmanTree.getEncodingArray();

        freqArray = mainHuffmanTree.getFrequenceArray();
    }

    public HuffmanOperator() {}//for extract;

    //---------------------------------------compression-----------------------------------------------------------
    private String getCompressedString() {
        String compressed = "";
        String intermidiate = "";//промежуточная строка(без добавочных нулей)
        //System.out.println("=============================Compression=======================");
        //displayEncodingArray();
        for (int i = 0; i < myString.length(); i++) {
            intermidiate += encodingArray[myString.charAt(i)];
        }
        //Мы не можем писать бит в файл. Поэтому нужно сделать длину сообщения кратной 8=>
        //нужно добавить нули в конец(можно 1, нет разницы)
        byte counter = 0;//количество добавленных в конец нулей (байта в полне хватит: 0<=counter<8<127)
        for (int length = intermidiate.length(), delta = 8 - length % 8; 
        		counter < delta ; counter++) {//delta - количество добавленных нулей
            intermidiate += "0";
        }
        
        //склеить кол-во добавочных нулей в бинарном предаствлении и промежуточную строку 
        compressed = String.format("%8s", Integer.toBinaryString(counter & 0xff)).replace(" ", "0") + intermidiate;
        		
        //идеализированный коэффициент
        setCompressionRatio();
        //System.out.println("===============================================================");
        return compressed;
    }
    
    private void setCompressionRatio() {//посчитать идеализированный коэффициент 
        double sumA = 0, sumB = 0;//A-the original sum
        for (int i = 0; i < ENCODING_TABLE_SIZE; i++) {
            if (freqArray[i] != 0) {
                sumA += 8 * freqArray[i];
                sumB += encodingArray[i].length() * freqArray[i];
            }
        }
        ratio = sumA / sumB;
    }

    public byte[] getBytedMsg() {//final compression
        StringBuilder compressedString = new StringBuilder(getCompressedString());
        byte[] compressedBytes = new byte[compressedString.length() / 8];
        for (int i = 0; i < compressedBytes.length; i++) {
                compressedBytes[i] = (byte) Integer.parseInt(compressedString.substring(i * 8, (i + 1) * 8), 2);
        }
        return compressedBytes;
    }
    //---------------------------------------end of compression----------------------------------------------------------------
    //------------------------------------------------------------extract-----------------------------------------------------
    public String extract(String compressed, String[] newEncodingArray) {
        String decompressed = "";
        String current = "";
        String delta = "";
        encodingArray = newEncodingArray;
        
        //displayEncodingArray();
        //получить кол-во вставленных нулей
        for (int i = 0; i < 8; i++) 
        	delta += compressed.charAt(i);
        int ADDED_ZEROES = Integer.parseInt(delta, 2);
       
        for (int i = 8, l = compressed.length() - ADDED_ZEROES; i < l; i++) {
            //i = 8, т.к. первым байтом у нас идет кол-во вставленных нулей
            current += compressed.charAt(i);
            for (int j = 0; j < ENCODING_TABLE_SIZE; j++) {
                if (current.equals(encodingArray[j])) {//если совпало
                    decompressed += (char)j;//то добавляем элемент
                    current = "";//и обнуляем текущую строку
                }
            }
        }

        return decompressed;
    }

    public String getEncodingTable() {
        String enc = "";
    	for (int i = 0; i < encodingArray.length; i++) {
        	if (freqArray[i] != 0) 
        		enc += (char)i + encodingArray[i] + 'n';
        }
    	return enc;
    }

    public double getCompressionRatio() {
        return ratio;
    }


    public void displayEncodingArray() {//для отладки
        System.out.println("======================Encoding table====================");
        for (int i = 0; i < ENCODING_TABLE_SIZE; i++) {
            //if (freqArray[i] != 0) {
                System.out.print((char)i + " ");
                System.out.println(encodingArray[i]);
            //}
        }
        System.out.println("========================================================");
    }
    }

Klas na-eme ka ọ dị mfe ide na faịlụ:

import java.io.File;
import java.io.PrintWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Closeable;

public class FileOutputHelper implements Closeable {
    private File outputFile;
    private FileOutputStream fileOutputStream;

    public FileOutputHelper(File file) throws FileNotFoundException {
        outputFile = file;
        fileOutputStream = new FileOutputStream(outputFile);
    }

    public void writeByte(byte msg) throws IOException {
        fileOutputStream.write(msg);
    }

    public void writeBytes(byte[] msg) throws IOException {
        fileOutputStream.write(msg);
    }

    public void writeString(String msg) {
    	try (PrintWriter pw = new PrintWriter(outputFile)) {
    		pw.write(msg);
    	} catch (FileNotFoundException e) {
    		System.out.println("Неверный путь, или такого файла не существует!");
    	}
    }

    @Override
    public void close() throws IOException {
        fileOutputStream.close();
    }

    public void finalize() throws IOException {
        close();
    }
}

Klas na-eme ka ọ dị mfe ịgụ site na faịlụ:

import java.io.FileInputStream;
import java.io.EOFException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;

public class FileInputHelper implements Closeable {
	private FileInputStream fileInputStream;
	private BufferedReader fileBufferedReader;
	
	public FileInputHelper(File file) throws IOException {
		fileInputStream = new FileInputStream(file);
		fileBufferedReader = new BufferedReader(new InputStreamReader(fileInputStream));
	}
	
	
    public byte readByte() throws IOException {
    	int cur = fileInputStream.read();
    	if (cur == -1)//если закончился файл
    		throw new EOFException();
    	return (byte)cur;
    }
    
    public String readLine() throws IOException {
    	return fileBufferedReader.readLine();
    }
    
    @Override
    public void close() throws IOException{
    	fileInputStream.close();
    }
}

Ọfọn, na isi klas:

import java.io.File;
import java.nio.charset.MalformedInputException;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Paths;
import java.util.List;
import java.io.EOFException;
public class Main {
	private static final byte ENCODING_TABLE_SIZE = 127;
	
    public static void main(String[] args) throws IOException {
        try {//указываем инструкцию с помощью аргументов командной строки
            if (args[0].equals("--compress") || args[0].equals("-c"))
                compress(args[1]);
            else if ((args[0].equals("--extract") || args[0].equals("-x"))
            		&& (args[2].equals("--table") || args[2].equals("-t"))) {
            	extract(args[1], args[3]);
            }
            else
                throw new IllegalArgumentException();
        } catch (ArrayIndexOutOfBoundsException | IllegalArgumentException e) {
            System.out.println("Неверный формат ввода аргументов ");
            System.out.println("Читайте Readme.txt");
            e.printStackTrace();
        }
    }

	public static void compress(String stringPath) throws IOException {
        List<String> stringList;
        File inputFile = new File(stringPath);
        String s = "";
        File compressedFile, table;
        
        try {
            stringList = Files.readAllLines(Paths.get(inputFile.getAbsolutePath()));
        } catch (NoSuchFileException e) {
            System.out.println("Неверный путь, или такого файла не существует!");
            return;
        } catch (MalformedInputException e) {
        	System.out.println("Текущая кодировка файла не поддерживается");
        	return;
        }

        for (String item : stringList) {
            s += item;
            s += 'n';
        }

        HuffmanOperator operator = new HuffmanOperator(new HuffmanTree(s));

        compressedFile = new File(inputFile.getAbsolutePath() + ".cpr");
        compressedFile.createNewFile();
        try (FileOutputHelper fo = new FileOutputHelper(compressedFile)) {
        	fo.writeBytes(operator.getBytedMsg());
        }
        //create file with encoding table:
        
        table = new File(inputFile.getAbsolutePath() + ".table.txt");
        table.createNewFile();
        try (FileOutputHelper fo = new FileOutputHelper(table)) {
        	fo.writeString(operator.getEncodingTable());
        }
        
        System.out.println("Путь к сжатому файлу: " + compressedFile.getAbsolutePath());
        System.out.println("Путь к кодировочной таблице " + table.getAbsolutePath());
        System.out.println("Без таблицы файл будет невозможно извлечь!");
        
        double idealRatio = Math.round(operator.getCompressionRatio() * 100) / (double) 100;//идеализированный коэффициент
        double realRatio = Math.round((double) inputFile.length() 
        		/ ((double) compressedFile.length() + (double) table.length()) * 100) / (double)100;//настоящий коэффициент
        
        System.out.println("Идеализированный коэффициент сжатия равен " + idealRatio);
        System.out.println("Коэффициент сжатия с учетом кодировочной таблицы " + realRatio);
    }

    public static void extract(String filePath, String tablePath) throws FileNotFoundException, IOException {
        HuffmanOperator operator = new HuffmanOperator();
        File compressedFile = new File(filePath),
        	 tableFile = new File(tablePath),
        	 extractedFile = new File(filePath + ".xtr");
        String compressed = "";
        String[] encodingArray = new String[ENCODING_TABLE_SIZE];
        //read compressed file
        //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!check here:
        try (FileInputHelper fi = new FileInputHelper(compressedFile)) {
        	byte b;
        	while (true) {
        		b = fi.readByte();//method returns EOFException
        		compressed += String.format("%8s", Integer.toBinaryString(b & 0xff)).replace(" ", "0");
        	}
        } catch (EOFException e) {
        	
        }
        
        //--------------------
        
        //read encoding table:
        try (FileInputHelper fi = new FileInputHelper(tableFile)) {
        	fi.readLine();//skip first empty string
        	encodingArray[(byte)'n'] = fi.readLine();//read code for 'n'
        	while (true) {
        		String s = fi.readLine();
        		if (s == null)
        			throw new EOFException();
        		encodingArray[(byte)s.charAt(0)] = s.substring(1, s.length());        		
        	}
        } catch (EOFException ignore) {}
        
        extractedFile.createNewFile();
        //extract:
		try (FileOutputHelper fo = new FileOutputHelper(extractedFile)) {
			fo.writeString(operator.extract(compressed, encodingArray));
		}
		
		System.out.println("Путь к распакованному файлу " + extractedFile.getAbsolutePath());
    }
}

Ị ga-ede faịlụ readme.txt n'onwe gị :)

nkwubi

Echere m na ọ bụ naanị ihe m chọrọ ikwu. Ọ bụrụ na ị nwere ihe ọ bụla ị ga-ekwu maka enweghị m ike imezi koodu, algọridim, ma ọ bụ njikarịcha ọ bụla n'ozuzu, mgbe ahụ nweere onwe gị ide. Ọ bụrụ na akọghị m ihe ọ bụla, biko deekwa. Ọ ga-amasị m ịnụ gị na nkwupụta!

PS

Ee, ee, m ka nọ ebe a, n'ihi na echefughị ​​m banyere ọnụọgụgụ. Maka eriri s1, tebụl ngbanwe ahụ na-atụ 48 bytes - nke ukwuu karịa faịlụ isi mmalite, anyị echefughị ​​maka zeros agbakwunyere (ọnụọgụ efu agbakwunyere bụ 7) => oke mkpakọ ga-erughị otu: 176/ (65 + 48*8 + 7) = 0.38. Ọ bụrụ na ị chọpụtakwara nke a, ọ bụghị naanị ihu gị ka mma. Ee, mmejuputa a ga-abụ nke na-adịghị mma maka obere faịlụ. Ma gịnị na-eme nnukwu faịlụ? Nha faịlụ dị ukwuu karịa nha nke tebụl ngbanwe. Nke a bụ ebe algọridim na-arụ ọrụ dị ka o kwesịrị! Dịka ọmụmaatụ, maka Okwu monologue Faust Onye na-edebe akwụkwọ akụkọ na-emepụta ezigbo ọnụọgụ (anaghị adị mma) nke 1.46 - ihe fọrọ nke nta ka ọ bụrụ otu oge na ọkara! Ma ee, faịlụ ahụ kwesịrị ịbụ na Bekee.

isi: www.habr.com

Tinye a comment