Comhbhrú sonraí le algartam Huffman

Iontráil

San Airteagal seo beidh mé ag caint faoi algartam cáiliúil Huffman, chomh maith lena chur i bhfeidhm i gcomhbhrú sonraí.

Mar thoradh air sin, scríobhfaimid cartlannóir simplí. Tá sé seo pléite cheana féin alt ar Habré, ach gan cur i bhfeidhm praiticiúil. Tógtar ábhar teoiriciúil an phoist reatha ó cheachtanna ríomheolaíochta scoile agus leabhar Robert Laforet “Data Structures and Algorithms in Java”. Mar sin, tá gach rud gearrtha!

Cúpla smaoineamh

I gcomhad téacs rialta, tá carachtar amháin ionchódaithe le 8 ngiotán (ionchódú ASCII) nó 16 (ionchódú Unicode). Ansin déanfaimid breithniú ar ionchódú ASCII. Mar shampla, tóg an líne s1 = “DEIR SUSIE IS É EASYn”. Tá iomlán de 22 carachtar sa líne, go nádúrtha, lena n-áirítear spásanna agus an carachtar líne nua - 'n'. Meáchan 22*8 = 176 giotán an comhad ina bhfuil an líne seo. Éiríonn an cheist láithreach: an bhfuil sé réasúnach na 8 ngiotán go léir a úsáid chun 1 charachtar a ionchódú? Ní úsáidimid gach carachtar ASCII. Fiú dá ndéanfaidís, bheadh ​​sé níos réasúnach an cód is giorra is féidir a thabhairt don litir is coitianta - S - agus cód níos faide a thabhairt don litir is neamhchoitianta - T (nó U, nó 'n'). Seo é atá in algartam Huffman: is gá an rogha ionchódaithe is fearr a aimsiú ina mbeidh an t-íosmhéid meáchain ag an gcomhad. Tá sé gnáth go leor go mbeidh na faid chóid difriúil le haghaidh siombailí éagsúla - is é seo a bhfuil an algartam bunaithe.

Códú

Cén fáth nach dtugann tú cód don charachtar 'S', mar shampla, 1 ghiotán ar fad: 0 nó 1. Bíodh sé 1. Ansin an dara carachtar is coitianta - ' ' (spás) - tabhair 0. Samhlaigh gur thosaigh tú ag díchódú do theachtaireachta - an teaghrán ionchódaithe s1 - agus feiceann tú go dtosaíonn an cód le 1. Mar sin, cad a dhéanann tú: an é seo an carachtar S, nó an carachtar éigin eile é, mar shampla A? Mar sin, tagann riail thábhachtach chun cinn:

Níor cheart go mbeadh ceachtar den dá chód ina réimír de chód eile

Tá an riail seo ríthábhachtach san algartam. Mar sin, tosaíonn cruthú cód le tábla minicíochta, a léiríonn minicíocht (líon tarluithe) gach siombail:

Comhbhrú sonraí le algartam Huffman Ba cheart na carachtair is mó tarluithe a ionchódú féidir líon giotán. Tabharfaidh mé sampla de cheann de na táblaí cód féideartha:

Comhbhrú sonraí le algartam Huffman Mar sin beidh cuma mar seo ar an teachtaireacht ionchódaithe:

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

Scar mé cód gach carachtar le spás. Ní tharlóidh sé seo i gcomhad fíor-chomhbhrúite!
Éiríonn an cheist: conas a tháinig an fear óg seo suas leis an gcód chun tábla cóid a chruthú? Déanfar é seo a phlé thíos.

Crann Huffman a thógáil

Seo nuair a thagann crainn chuardaigh dhénártha chun an tarrthála. Ná bí buartha, ní bheidh na modhanna cuardaigh, cuir isteach nó scriosta uait anseo. Seo é struchtúr na gcrann i 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;
    }
    ...
}

Ní hé seo an cód iomlán, beidh an cód iomlán thíos.

Seo é an algartam chun an crann a thógáil:

  1. Cruthaigh réad Nód do gach carachtar ón teachtaireacht (líne s1). In ár gcás beidh 9 nóid (Rudaí Nód). Tá dhá réimse sonraí i ngach nód: siombail agus minicíocht
  2. Cruthaigh réad Crann (BinaryTree) do gach Nód. Éiríonn an nód mar fhréamh an chrainn.
  3. Cuir na crainn seo isteach sa scuaine tosaíochta. Dá ísle an minicíocht, is airde an tosaíocht. Mar sin, nuair a bhaintear amach, roghnaítear an dervo leis an minicíocht is ísle i gcónaí.

Ansin ní mór duit na rudaí seo a leanas a dhéanamh go timthriallach:

  1. Bain dhá chrann as an scuaine tosaíochta agus iad a dhéanamh leanaí an nód nua (an nód nuachruthaithe gan an litir). Tá minicíocht an nód nua comhionann le suim mhinicíochtaí an dá chrann sliocht.
  2. Chun an nód seo, cruthaigh crann leis an bhfréamh ag an nód seo. Cuir an crann seo ar ais sa scuaine tosaíochta. (Ós rud é go bhfuil minicíocht nua ag an gcrann, is dóichí go mbeidh sé le feiceáil in áit nua sa scuaine)
  3. Lean ar aghaidh le céimeanna 1 agus 2 go dtí nach bhfuil ach crann amháin fágtha sa scuaine - an crann Huffman

Smaoinigh ar an algartam seo ar líne s1:

Comhbhrú sonraí le algartam Huffman

Anseo ciallaíonn an tsiombail “lf” (linefeed) líne nua, is spás é “sp” (spás).

Agus ansin cad?

Fuaireamar crann Huffman. ceart go leor. Agus cad atá le déanamh leis? Ní ghlacfaidh siad fiú saor in aisce é. Aontaímid imeall 0 má leanann sé go dtí an leanbh ar chlé agus 1 má leanann sé go dtí an leanbh ceart. Go docht, sa nodaireacht seo, is é cód siombail an chonair ó fhréamh an chrainn go dtí an duilleog ina bhfuil an tsiombail seo.

Comhbhrú sonraí le algartam Huffman

Seo mar a tháinig an tábla cóid amach. Tabhair faoi deara, má dhéanaimid machnamh ar an tábla seo, is féidir linn an tátal a bhaint as “meáchan” gach siombaile - is é seo fad a chóid. Ansin, i bhfoirm chomhbhrúite, meáigh an comhad bunaidh: 2 * 3 + 2 * 4 + 3 * 3 + 6 * 2 + 1 * 4 + 1 * 5 + 2 * 4 + 4 * 2 + 1 * 5 = 65 giotán . Ar dtús mheáigh sé 176 giotán. Mar thoradh air sin, laghdaigh muid é chomh mór le 176/65 = 2.7 uair! Ach is utopia é seo. Ní dócha go bhfaighfear comhéifeacht den sórt sin. Cén fáth? Déanfar é seo a phlé beagán níos déanaí.

Díchódaithe

Bhuel, b'fhéidir gurb é an rud is simplí atá fágtha ná díchódú. Sílim go bhfuil go leor agaibh tar éis buille faoi thuairim nach féidir linn comhad comhbhrúite a chruthú gan aon leid ar conas a ionchódaíodh é - ní bheimid in ann é a dhíchódú! Sea, bhí, bhí sé deacair dom é seo a bhaint amach, ach beidh orm tábla comhaid téacs.txt a chruthú le tábla comhbhrú:

01110
 00
A010
E1111
I110
S10
T0110
U01111
Y1110

Iontráil tábla san fhoirm 'siombail' 'cód carachtair'. Cén fáth a bhfuil 01110 gan siombail? Go deimhin, is le siombail é, níl ann ach na huirlisí java a úsáidim agus mé ag aschur go comhad, déantar an carachtar nualíne - 'n' - a thiontú ina líne nua (is cuma cé chomh dúr is féidir leis). Mar sin, is é an líne folamh ag an mbarr an carachtar le haghaidh cód 01110. Le haghaidh cód 00, is spás é an carachtar ag tús na líne. Déarfaidh mé ar an bpointe boise le haghaidh ár gcomhéifeacht Khan, go bhféadfadh an modh seo chun tábla a stóráil a rá gurb é an modh is neamhréasúnach é. Ach tá sé éasca a thuiscint agus a chur i bhfeidhm. Beidh áthas orm do mholtaí a chloisteáil sna tuairimí maidir le leas iomlán a bhaint.

Tá sé an-éasca an tábla seo a dhíchódú. Cuimhnímis ar an riail a leanamar agus an t-ionchódú á chruthú:

Níor cheart go mbeadh ceachtar den dá chód ina réimír de chód eile

Seo an áit a bhfuil ról éascaithe aige. Léimid go seicheamhach beagán ar giotán agus, a luaithe a mheaitseálann an teaghrán d mar thoradh air, comhdhéanta de na giotán léite, an t-ionchódú a fhreagraíonn do charachtar an charachtair, tá a fhios againn láithreach go raibh an carachtar carachtair (agus é!) ionchódaithe. Ansin, scríobhaimid carachtar isteach sa líne díchódaithe (an líne ina bhfuil an teachtaireacht díchódaithe), athshocraigh líne d, agus ansin léigh an comhad ionchódaithe.

Cur i bhFeidhm

Tá sé in am agam mo chód a náiriú agus cartlannóir a scríobh. A ligean ar a dtugtar é Compressor.

Thosaigh arís. Ar dtús, scríobhaimid an rang Nód:

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

Anois an crann:

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

Ciú Tosaíochta:

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;//возвращаем удаленный элемент(элемент с наименьшей частотой)
    }
}

An rang a chruthaíonn an crann 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;
    }
}

Aicme ina bhfuil a ionchódaíonn/a dhíchódaíonn:

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

Rang a éascaíonn scríobh chuig comhad:

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

Rang a éascaíonn é a léamh ó chomhad:

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

Bhuel, agus an príomh rang:

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

Beidh ort an comhad readme.txt a scríobh tú féin :)

Conclúid

Is dóigh liom gurb é sin go léir a theastaigh uaim a rá. Má tá aon rud le rá agat faoi mo neamhinniúlacht maidir le feabhas a chur ar an gcód, algartam, nó aon leas iomlán a bhaint i gcoitinne, ansin bíodh leisce ort scríobh. Mura bhfuil aon rud mínithe agam, scríobh freisin. Ba bhreá liom cloisteáil uait sna tuairimí!

PS

Sea, tá, tá mé fós anseo, mar ní dhearna mé dearmad ar an gcomhéifeacht. Maidir le teaghrán s1, tá meáchan an tábla ionchódaithe 48 bytes - i bhfad níos mó ná an comhad foinse, agus ní dhearna muid dearmad faoi na nialais breise (is é líon na nialais breise 7) => beidh an cóimheas comhbhrú níos lú ná a haon: 176/ (65 + 48*8 + 7) = 0.38 . Má thug tú é seo faoi deara freisin, ní hé d’aghaidh amháin atá iontach. Sea, beidh an cur chun feidhme seo thar a bheith mí-éifeachtach do chomhaid bheaga. Ach cad a tharlaíonn do chomhaid mhóra? Tá méideanna comhaid i bhfad níos mó ná méid an tábla ionchódaithe. Seo an áit a n-oibríonn an algartam mar ba chóir! Mar shampla, le haghaidh Monologue Faust Táirgeann an cartlannóir fíor-chomhéifeacht (nach bhfuil idéalach) de 1.46 - beagnach uair go leith! Agus sea, bhí an file ceaptha a bheith i mBéarla.

Foinse: will.com

Add a comment