Π‘ΠΆΠ°Ρ‚ΠΈΠ΅ Π΄Π°Π½Π½Ρ‹Ρ… Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΠΎΠΌ Π₯Π°Ρ„Ρ„ΠΌΠ°Π½Π°

ВступлСниС

Π’ Π΄Π°Π½Π½ΠΎΠΉ ΡΡ‚Π°Ρ‚ΡŒΠ΅ я расскаТу ΠΎΠ± извСстном Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΠ΅ Π₯Π°Ρ„Ρ„ΠΌΠ°Π½Π°, Π° Ρ‚Π°ΠΊΠΆΠ΅ ΠΎ Π΅Π³ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠΈ Π² сТатии Π΄Π°Π½Π½Ρ‹Ρ….

Π’ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π΅ напишСм ΠΏΡ€ΠΎΡΡ‚Π΅Π½ΡŒΠΊΠΈΠΉ Π°Ρ€Ρ…ΠΈΠ²Π°Ρ‚ΠΎΡ€. Об этом ΡƒΠΆΠ΅ Π±Ρ‹Π»Π° ΡΡ‚Π°Ρ‚ΡŒΡ Π½Π° Π₯Π°Π±Ρ€Π΅, Π½ΠΎ Π±Π΅Π· практичСской Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ. ВСорСтичСский ΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π» Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ поста взят ΠΈΠ· ΡˆΠΊΠΎΠ»ΡŒΠ½Ρ‹Ρ… ΡƒΡ€ΠΎΠΊΠΎΠ² ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ΠΈΠΊΠΈ ΠΈ ΠΊΠ½ΠΈΠ³ΠΈ Π ΠΎΠ±Π΅Ρ€Ρ‚Π° Π›Π°Ρ„ΠΎΡ€Π΅ Β«Data Structures and Algorithms in JavaΒ». Π˜Ρ‚Π°ΠΊ, всС ΠΏΠΎΠ΄ ΠΊΠ°Ρ‚!

НСмного Ρ€Π°Π·ΠΌΡ‹ΡˆΠ»Π΅Π½ΠΈΠΉ

Π’ ΠΎΠ±Ρ‹Ρ‡Π½ΠΎΠΌ тСкстовом Ρ„Π°ΠΉΠ»Π΅ ΠΎΠ΄ΠΈΠ½ символ кодируСтся 8 Π±ΠΈΡ‚Π°ΠΌΠΈ(ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²ΠΊΠ° ASCII) ΠΈΠ»ΠΈ 16(ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²ΠΊΠ° Unicode). Π”Π°Π»Π΅Π΅ Π±ΡƒΠ΄Π΅ΠΌ Ρ€Π°ΡΡΠΌΠ°Ρ‚Ρ€ΠΈΠ²Π°Ρ‚ΡŒ ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²ΠΊΡƒ ASCII. Для ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π° возьмСм строку s1 = Β«SUSIE SAYS IT IS EASYnΒ». ВсСго Π² строкС 22 символа, СстСствСнно, Π²ΠΊΠ»ΡŽΡ‡Π°Ρ ΠΏΡ€ΠΎΠ±Π΅Π»Ρ‹ ΠΈ символ ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄Π° Π½Π° Π½ΠΎΠ²ΡƒΡŽ строку β€” ‘n’. Π€Π°ΠΉΠ», содСрТащий Π΄Π°Π½Π½ΡƒΡŽ строку Π±ΡƒΠ΄Π΅Ρ‚ Π²Π΅ΡΠΈΡ‚ΡŒ 22*8 = 176 Π±ΠΈΡ‚. Π‘Ρ€Π°Π·Ρƒ ΠΆΠ΅ встаСт вопрос: Ρ€Π°Ρ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎ Π»ΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ всС 8 Π±ΠΈΡ‚ для ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²ΠΊΠΈ 1 символа? ΠœΡ‹ вСдь ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ Π½Π΅ всС символы ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²ΠΊΠΈ ASCII. Π”Π°ΠΆΠ΅ Ссли Π±Ρ‹ ΠΈ использовали, Ρ€Π°Ρ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½Π΅ΠΉ Π±Ρ‹Π»ΠΎ Π±Ρ‹ самой частой Π±ΡƒΠΊΠ²Π΅ β€” S β€” Π΄Π°Ρ‚ΡŒ самый ΠΊΠΎΡ€ΠΎΡ‚ΠΊΠΈΠΉ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½Ρ‹ΠΉ ΠΊΠΎΠ΄, Π° для самой Ρ€Π΅Π΄ΠΊΠΎΠΉ Π±ΡƒΠΊΠ²Π΅ β€” T (ΠΈΠ»ΠΈ U, ΠΈΠ»ΠΈ ‘n’) β€” Π΄Π°Ρ‚ΡŒ ΠΊΠΎΠ΄ ΠΏΠΎΠ΄Π»ΠΈΠ½Π½Π΅Π΅. Π’ этом ΠΈ Π·Π°ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ΡΡ Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌ Π₯Π°Ρ„Ρ„ΠΌΠ°Π½Π°: Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ Π½Π°ΠΉΡ‚ΠΈ ΠΎΠΏΡ‚ΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²ΠΊΠΈ, ΠΏΡ€ΠΈ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ Ρ„Π°ΠΉΠ» Π±ΡƒΠ΄Π΅Ρ‚ минимального вСса. Π’ΠΏΠΎΠ»Π½Π΅ Π½ΠΎΡ€ΠΌΠ°Π»ΡŒΠ½ΠΎ, Ρ‡Ρ‚ΠΎ Ρƒ Ρ€Π°Π·Π½Ρ‹Ρ… символов Π΄Π»ΠΈΠ½Ρ‹ ΠΊΠΎΠ΄Π° Π±ΡƒΠ΄ΡƒΡ‚ ΠΎΡ‚Π»ΠΈΡ‡Π°Ρ‚ΡŒΡΡ β€” Π½Π° этом ΠΈ основан Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌ.

ΠšΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅

ΠŸΠΎΡ‡Π΅ΠΌΡƒ Π±Ρ‹ символу ‘S’ Π½Π΅ Π΄Π°Ρ‚ΡŒ ΠΊΠΎΠ΄, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Π΄Π»ΠΈΠ½ΠΎΠΉ Π² 1 Π±ΠΈΡ‚: 0 ΠΈΠ»ΠΈ 1. ΠŸΡƒΡΡ‚ΡŒ это Π±ΡƒΠ΄Π΅Ρ‚ 1. Π’ΠΎΠ³Π΄Π° Π²Ρ‚ΠΎΡ€ΠΎΠΌΡƒ Π½Π°ΠΈΠ±ΠΎΠ»Π΅Π΅ Π²ΡΡ‚Ρ€Π΅Ρ‡Π°ΡŽΡ‰Π΅ΠΌΡƒΡΡ символу β€” ‘ ‘(ΠΏΡ€ΠΎΠ±Π΅Π») β€” Π΄Π°Π΄ΠΈΠΌ 0. ΠŸΡ€Π΅Π΄ΡΡ‚Π°Π²ΡŒΡ‚Π΅ сСбС, Π²Ρ‹ Π½Π°Ρ‡Π°Π»ΠΈ Π΄Π΅ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ своС сообщСниС β€” Π·Π°ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Π½Π½ΡƒΡŽ строку s1 β€” ΠΈ Π²ΠΈΠ΄ΠΈΡ‚Π΅, Ρ‡Ρ‚ΠΎ ΠΊΠΎΠ΄ начинаСтся с 1. Π˜Ρ‚Π°ΠΊ, Ρ‡Ρ‚ΠΎ ΠΆΠ΅ Π΄Π΅Π»Π°Ρ‚ΡŒ: это символ S, ΠΈΠ»ΠΈ ΠΆΠ΅ это ΠΊΠ°ΠΊΠΎΠΉ-Ρ‚ΠΎ Π΄Ρ€ΡƒΠ³ΠΎΠΉ символ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ A? ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π΅Ρ‚ Π²Π°ΠΆΠ½ΠΎΠ΅ ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ:

Ни ΠΎΠ΄ΠΈΠ½ ΠΊΠΎΠ΄ Π½Π΅ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Ρ‚ΡŒ прСфиксом Π΄Ρ€ΡƒΠ³ΠΎΠ³ΠΎ

Π­Ρ‚ΠΎ ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ являСтся ΠΊΠ»ΡŽΡ‡Π΅Π²Ρ‹ΠΌ Π² Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΠ΅. ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ созданиС ΠΊΠΎΠ΄Π° начинаСтся с частотной Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ ΡƒΠΊΠ°Π·Π°Π½Π° частота (количСство Π²Ρ…ΠΎΠΆΠ΄Π΅Π½ΠΈΠΉ) ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ символа:

Π‘ΠΆΠ°Ρ‚ΠΈΠ΅ Π΄Π°Π½Π½Ρ‹Ρ… Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΠΎΠΌ Π₯Π°Ρ„Ρ„ΠΌΠ°Π½Π° Π‘ΠΈΠΌΠ²ΠΎΠ»Ρ‹ с наибольшим количСством Π²Ρ…ΠΎΠΆΠ΄Π΅Π½ΠΈΠΉ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒΡΡ наимСньшим Π²ΠΎΠ·ΠΌΠΎΠΆΠ½Ρ‹ΠΌ количСством Π±ΠΈΡ‚ΠΎΠ². ΠŸΡ€ΠΈΠ²Π΅Π΄Ρƒ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ ΠΎΠ΄Π½ΠΎΠΉ ΠΈΠ· Π²ΠΎΠ·ΠΌΠΎΠΆΠ½Ρ‹Ρ… Ρ‚Π°Π±Π»ΠΈΡ† ΠΊΠΎΠ΄ΠΎΠ²:

Π‘ΠΆΠ°Ρ‚ΠΈΠ΅ Π΄Π°Π½Π½Ρ‹Ρ… Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΠΎΠΌ Π₯Π°Ρ„Ρ„ΠΌΠ°Π½Π° Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, Π·Π°ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎΠ΅ сообщСниС Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π³Π»ΡΠ΄Π΅Ρ‚ΡŒ Ρ‚Π°ΠΊ:

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

Код ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ символа я Ρ€Π°Π·Π΄Π΅Π»ΠΈΠ» ΠΏΡ€ΠΎΠ±Π΅Π»ΠΎΠΌ. По-настоящСму Π² сТатом Ρ„Π°ΠΉΠ»Π΅ Ρ‚Π°ΠΊΠΎΠ³ΠΎ Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚!
Π’Ρ‹Ρ‚Π΅ΠΊΠ°Π΅Ρ‚ вопрос: ΠΊΠ°ΠΊ этот салага ΠΏΡ€ΠΈΠ΄ΡƒΠΌΠ°Π» ΠΊΠΎΠ΄ ΠΊΠ°ΠΊ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ ΠΊΠΎΠ΄ΠΎΠ²? Об этом ΠΏΠΎΠΉΠ΄Π΅Ρ‚ Ρ€Π΅Ρ‡ΡŒ Π½ΠΈΠΆΠ΅.

ΠŸΠΎΡΡ‚Ρ€ΠΎΠ΅Π½ΠΈΠ΅ Π΄Π΅Ρ€Π΅Π²Π° Π₯Π°Ρ„Ρ„ΠΌΠ°Π½Π°

Π—Π΄Π΅ΡΡŒ приходят Π½Π° Π²Ρ‹Ρ€ΡƒΡ‡ΠΊΡƒ Π±ΠΈΠ½Π°Ρ€Π½Ρ‹Π΅ Π΄Π΅Ρ€Π΅Π²ΡŒΡ поиска. НС Π²ΠΎΠ»Π½ΡƒΠΉΡ‚Π΅ΡΡŒ, здСсь ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ поиска, вставки ΠΈ удалСния Π½Π΅ ΠΏΠΎΡ‚Ρ€Π΅Π±ΡƒΡŽΡ‚ΡΡ. Π’ΠΎΡ‚ структура Π΄Π΅Ρ€Π΅Π²Π° Π½Π° 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;
    }
    ...
}

Π­Ρ‚ΠΎ Π½Π΅ ΠΏΠΎΠ»Π½Ρ‹ΠΉ ΠΊΠΎΠ΄, ΠΏΠΎΠ»Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ Π±ΡƒΠ΄Π΅Ρ‚ Π½ΠΈΠΆΠ΅.

Π’ΠΎΡ‚ сам Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌ построСния Π΄Π΅Ρ€Π΅Π²Π°:

  1. Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ Node для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ символа ΠΈΠ· сообщСния(строка s1). Π’ нашСм случаС Π±ΡƒΠ΄Π΅Ρ‚ 9 ΡƒΠ·Π»ΠΎΠ²(ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² Node). ΠšΠ°ΠΆΠ΄Ρ‹ΠΉ ΡƒΠ·Π΅Π» состоит ΠΈΠ· Π΄Π²ΡƒΡ… ΠΏΠΎΠ»Π΅ΠΉ Π΄Π°Π½Π½Ρ‹Ρ…: символ ΠΈ частота
  2. Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ Π”Π΅Ρ€Π΅Π²Π°(BinaryTree) для ΠΊΠ°ΠΆΠ»ΠΎΠ³ΠΎ ΠΈΠ· ΡƒΠ·Π»ΠΎΠ² Node. Π£Π·Π΅Π» становится ΠΊΠΎΡ€Π½Π΅ΠΌ Π΄Π΅Ρ€Π΅Π²Π°.
  3. Π’ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ эти Π΄Π΅Ρ€Π΅Π²ΡŒΡ Π² ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚Π½ΡƒΡŽ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ. Π§Π΅ΠΌ мСньшС частота, Ρ‚Π΅ΠΌ большС ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚. Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, ΠΏΡ€ΠΈ ΠΈΠ·Π²Π»Π΅Ρ‡Π΅Π½ΠΈΠΈ всСгда выбираСтся Π΄Π΅Ρ€Π²ΠΎ наимСньшСй частотой.

Π”Π°Π»Π΅Π΅ Π½ΡƒΠΆΠ½ΠΎ цикличСски Π΄Π΅Π»Π°Ρ‚ΡŒ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π΅:

  1. Π˜Π·Π²Π»Π΅Ρ‡ΡŒ Π΄Π²Π° Π΄Π΅Ρ€Π΅Π²Π° ΠΈΠ· ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚Π½ΠΎΠΉ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ ΠΈ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ ΠΈΡ… ΠΏΠΎΡ‚ΠΎΠΌΠΊΠ°ΠΌΠΈ Π½ΠΎΠ²ΠΎΠ³ΠΎ ΡƒΠ·Π»Π° (Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ρ‡Ρ‚ΠΎ созданного ΡƒΠ·Π»Π° Π±Π΅Π· Π±ΡƒΠΊΠ²Ρ‹). Частота Π½ΠΎΠ²ΠΎΠ³ΠΎ ΡƒΠ·Π»Π° Ρ€Π°Π²Π½Π° суммС частот Π΄Π²ΡƒΡ… Π΄Π΅Ρ€Π΅Π²ΡŒΠ΅Π²-ΠΏΠΎΡ‚ΠΎΠΌΠΊΠΎΠ².
  2. Для этого ΡƒΠ·Π»Π° ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Π΄Π΅Ρ€Π΅Π²ΠΎ с ΠΊΠΎΡ€Π½Π΅ΠΌ Π² Π΄Π°Π½Π½ΠΎΠΌ ΡƒΠ·Π»Π΅. Π’ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ это Π΄Π΅Ρ€Π΅Π²ΠΎ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ Π² ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚Π½ΡƒΡŽ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ. (Π’Π°ΠΊ ΠΊΠ°ΠΊ Ρƒ Π΄Π΅Ρ€Π΅Π²Π° новая частота, Ρ‚ΠΎ скорСС всСго ΠΎΠ½Π° встанСт Π½Π° Π½ΠΎΠ²ΠΎΠ΅ мСсто Π² ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ)
  3. ΠŸΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠ°Ρ‚ΡŒ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ шагов 1 ΠΈ 2, ΠΏΠΎΠΊΠ° Π² ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ Π½Π΅ останСтся ΠΎΠ΄Π½ΠΎ Π΄Π΅Ρ€Π΅Π²ΠΎ β€” Π΄Π΅Ρ€Π΅Π²ΠΎ Π₯Π°Ρ„Ρ„ΠΌΠ°Π½Π°

Рассмотрим Π΄Π°Π½Π½Ρ‹ΠΉ Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌ Π½Π° строкС s1:

Π‘ΠΆΠ°Ρ‚ΠΈΠ΅ Π΄Π°Π½Π½Ρ‹Ρ… Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΠΎΠΌ Π₯Π°Ρ„Ρ„ΠΌΠ°Π½Π°

Π—Π΄Π΅ΡΡŒ символ Β«lfΒ»(linefeed) ΠΎΠ±ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚ ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ Π½Π° Π½ΠΎΠ²ΡƒΡŽ строку, Β«spΒ» (space) β€” это ΠΏΡ€ΠΎΠ±Π΅Π».

А Ρ‡Ρ‚ΠΎ дальшС?

ΠœΡ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΈ Π΄Π΅Ρ€Π΅Π²ΠΎ Π₯Π°Ρ„Ρ„ΠΌΠ°Π½Π°. Ну ΠΎΠΊΠ΅ΠΉ. И Ρ‡Ρ‚ΠΎ с Π½ΠΈΠΌ Π΄Π΅Π»Π°Ρ‚ΡŒ? Π•Π³ΠΎ ΠΈ Π·Π° бСсплатно Π½Π΅ Π²ΠΎΠ·ΡŒΠΌΡƒΡ‚ А Π΄Π°Π»Π΅Π΅, Π½ΡƒΠΆΠ½ΠΎ ΠΎΡ‚ΡΠ»Π΅Π΄ΠΈΡ‚ΡŒ всС Π²ΠΎΠ·ΠΌΠΎΠΆΠ½Ρ‹Π΅ ΠΏΡƒΡ‚ΠΈ ΠΎΡ‚ корня Π΄ΠΎ листов Π΄Π΅Ρ€Π΅Π²Π°. Условимся ΠΎΠ±ΠΎΠ·Π½Π°Ρ‡ΠΈΡ‚ΡŒ Ρ€Π΅Π±Ρ€ΠΎ 0, Ссли ΠΎΠ½ΠΎ Π²Π΅Π΄Π΅Ρ‚ ΠΊ Π»Π΅Π²ΠΎΠΌΡƒ ΠΏΠΎΡ‚ΠΎΠΌΠΊΡƒ ΠΈ 1 β€” Ссли ΠΊ ΠΏΡ€Π°Π²ΠΎΠΌΡƒ. Π‘Ρ‚Ρ€ΠΎΠ³ΠΎ говоря, Π² Π΄Π°Π½Π½Ρ‹Ρ… обозначСниях, ΠΊΠΎΠ΄ символа β€” это ΠΏΡƒΡ‚ΡŒ ΠΎΡ‚ корня Π΄Π΅Ρ€Π΅Π²Π° Π΄ΠΎ листа, содСрТащСго этот самый символ.

Π‘ΠΆΠ°Ρ‚ΠΈΠ΅ Π΄Π°Π½Π½Ρ‹Ρ… Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΠΎΠΌ Π₯Π°Ρ„Ρ„ΠΌΠ°Π½Π°

Π’Π°ΠΊΠΈΠΌ ΠΌΠ°ΠΊΠ°Ρ€ΠΎΠΌ ΠΈ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»Π°ΡΡŒ Ρ‚Π°Π±Π»ΠΈΡ†Π° ΠΊΠΎΠ΄ΠΎΠ². Π—Π°ΠΌΠ΅Ρ‚ΠΈΠΌ, Ρ‡Ρ‚ΠΎ Ссли Ρ€Π°ΡΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ эту Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ, Ρ‚ΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Π²Ρ‹Π²ΠΎΠ΄ ΠΎ «вСсС» ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ символа β€” это Π΄Π»ΠΈΠ½Π° Π΅Π³ΠΎ ΠΊΠΎΠ΄Π°. Π’ΠΎΠ³Π΄Π° Π² сТатом Π²ΠΈΠ΄Π΅ исходный Ρ„Π°ΠΉΠ» Π±ΡƒΠ΄Π΅Ρ‚ Π²Π΅ΡΠΈΡ‚ΡŒ: 2 * 3 + 2*4 + 3 * 3 + 6 * 2 + 1 * 4 + 1 * 5 + 2 * 4 + 4 * 2 + 1 * 5 = 65 Π±ΠΈΡ‚. Π’Π½Π°Ρ‡Π°Π»Π΅ ΠΎΠ½ вСсил 176 Π±ΠΈΡ‚. Π‘Π»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ, ΠΌΡ‹ ΡƒΠΌΠ΅Π½ΡŒΡˆΠΈΠ»ΠΈ Π΅Π³ΠΎ Π°ΠΆ Π² 176/65 = 2.7 Ρ€Π°Π·Π°! Но это утопия. Π’Π°ΠΊΠΎΠΉ коэффициСнт вряд Π»ΠΈ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½. ΠŸΠΎΡ‡Π΅ΠΌΡƒ? Об этом ΠΏΠΎΠΉΠ΄Π΅Ρ‚ Ρ€Π΅Ρ‡ΡŒ Ρ‡ΡƒΡ‚ΡŒ ΠΏΠΎΠ·ΠΆΠ΅.

Π”Π΅ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅

Ну, ΠΏΠΎΠΆΠ°Π»ΡƒΠΉ, ΠΎΡΡ‚Π°Π»ΠΎΡΡŒ самоС простоС β€” Π΄Π΅ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅. Π― Π΄ΡƒΠΌΠ°ΡŽ, ΠΌΠ½ΠΎΠ³ΠΈΠ΅ ΠΈΠ· вас догадались, Ρ‡Ρ‚ΠΎ просто ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ сТатый Ρ„Π°ΠΉΠ» Π±Π΅Π· ΠΊΠ°ΠΊΠΈΡ…-Π»ΠΈΠ±ΠΎ Π½Π°ΠΌΠ΅ΠΊΠΎΠ² Π½Π° Ρ‚ΠΎ, ΠΊΠ°ΠΊ ΠΎΠ½ Π±Ρ‹Π» Π·Π°ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Π½, нСльзя β€” ΠΌΡ‹ Π½Π΅ смоТСм Π΅Π³ΠΎ Π΄Π΅ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ! Π”Π°-Π΄Π°, ΠΌΠ½Π΅ Π±Ρ‹Π»ΠΎ тяТСло это ΠΎΡΠΎΠ·Π½Π°Ρ‚ΡŒ, Π½ΠΎ придСтся ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ тСкстовый Ρ„Π°ΠΉΠ» table.txt с Ρ‚Π°Π±Π»ΠΈΡ†Π΅ΠΉ сТатия:

01110
 00
A010
E1111
I110
S10
T0110
U01111
Y1110

Π—Π°ΠΏΠΈΡΡŒ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ Π² Π²ΠΈΠ΄Π΅ ‘символ’Β«ΠΊΠΎΠ΄ символа». ΠŸΠΎΡ‡Π΅ΠΌΡƒ 01110 Π±Π΅Π· символа? На самом Π΄Π΅Π»Π΅ ΠΎΠ½ с символом, просто срСдства java, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡ‹Π΅ ΠΌΠ½ΠΎΠΉ ΠΏΡ€ΠΈ Π²Ρ‹Π²ΠΎΠ΄Π΅ Π² Ρ„Π°ΠΉΠ», символ ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄Π° Π½Π° Π½ΠΎΠ²ΡƒΡŽ строку β€” ‘n’ -ΠΊΠΎΠ½Π²Π΅Ρ€Ρ‚ΠΈΡ€ΡƒΡŽΡ‚ Π² ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ Π½Π° Π½ΠΎΠ²ΡƒΡŽ строку(ΠΊΠ°ΠΊ Π±Ρ‹ это Π³Π»ΡƒΠΏΠΎ Π½Π΅ Π·Π²ΡƒΡ‡Π°Π»ΠΎ). ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ пустая строка свСрху ΠΈ Π΅ΡΡ‚ΡŒ символ для ΠΊΠΎΠ΄Π° 01110. Для ΠΊΠΎΠ΄Π° 00 символом являСтся ΠΏΡ€ΠΎΠ±Π΅Π» Π² Π½Π°Ρ‡Π°Π»Π΅ строки. Π‘Ρ€Π°Π·Ρƒ скаТу, Ρ‡Ρ‚ΠΎ Π½Π°ΡˆΠ΅ΠΌΡƒ коэффициСнту ханаэтот способ хранСния Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΡ€Π΅Ρ‚Π΅Π½Π΄ΠΎΠ²Π°Ρ‚ΡŒ Π½Π° самый Π½Π΅Ρ€Π°Ρ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½Ρ‹ΠΉ. Но ΠΎΠ½ прост для понимания ΠΈ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ. Π‘ ΡƒΠ΄ΠΎΠ²ΠΎΠ»ΡŒΡΡ‚Π²ΠΈΠ΅ΠΌ Π²Ρ‹ΡΠ»ΡƒΡˆΠ°ΡŽ Π’Π°ΡˆΠΈ Ρ€Π΅ΠΊΠΎΠΌΠ΅Π½Π΄Π°Ρ†ΠΈΠΈ Π² коммСнтариях ΠΏΠΎ ΠΏΠΎΠ²ΠΎΠ΄Ρƒ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ.

ИмСя эту Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ, ΠΎΡ‡Π΅Π½ΡŒ просто Π΄Π΅ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ. Вспомним, ΠΊΠ°ΠΊΠΈΠΌ ΠΏΡ€Π°Π²ΠΈΠ»ΠΎΠΌ ΠΌΡ‹ Ρ€ΡƒΠΊΠΎΠ²ΠΎΠ΄ΡΡ‚Π²ΠΎΠ²Π°Π»ΠΈΡΡŒ, ΠΏΡ€ΠΈ создании ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²ΠΊΠΈ:

Ни ΠΎΠ΄ΠΈΠ½ ΠΊΠΎΠ΄ Π½Π΅ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΡΠ²Π»ΡΡ‚ΡŒΡΡ прСфиксом Π΄Ρ€ΡƒΠ³ΠΎΠ³ΠΎ

Π’ΠΎΡ‚ Ρ‚ΡƒΡ‚-Ρ‚ΠΎ ΠΎΠ½ΠΎ ΠΈ ΠΈΠ³Ρ€Π°Π΅Ρ‚ ΠΎΠ±Π»Π΅Π³Ρ‡Π°ΡŽΡ‰ΡƒΡŽ Ρ€ΠΎΠ»ΡŒ. ΠœΡ‹ Ρ‡ΠΈΡ‚Π°Π΅ΠΌ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ Π±ΠΈΡ‚ Π·Π° Π±ΠΈΡ‚ΠΎΠΌ ΠΈ, ΠΊΠ°ΠΊ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ получСнная строка d, состоящая ΠΈΠ· ΠΏΡ€ΠΎΡ‡Ρ‚Π΅Π½Π½Ρ‹Ρ… Π±ΠΈΡ‚ΠΎΠ², совпадаСт с ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²ΠΊΠΎΠΉ, ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰Π΅ΠΉ символу character, ΠΌΡ‹ сразу Π·Π½Π°Π΅ΠΌ Ρ‡Ρ‚ΠΎ Π±Ρ‹Π» Π·Π°ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Π½ символ character (ΠΈ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠ½!). Π”Π°Π»Π΅Π΅ записываСм character Π² Π΄Π΅ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²ΠΎΡ‡Π½ΡƒΡŽ строку(строку, ΡΠΎΠ΄Π΅Ρ€ΠΆΠ°Ρ‰ΡƒΡŽ Π΄Π΅ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎΠ΅ сообщСниС), обнуляСм строку d, ΠΈ Ρ‡ΠΈΡ‚Π°Π΅ΠΌ дальшС Π·Π°ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ».

РСализация

ΠŸΡ€ΠΈΡˆΠ»ΠΎ врСмя ΡƒΠ½ΠΈΠΆΠ°Ρ‚ΡŒ ΠΌΠΎΠΉ ΠΊΠΎΠ΄ ΠΏΠΈΡΠ°Ρ‚ΡŒ Π°Ρ€Ρ…ΠΈΠ²Π°Ρ‚ΠΎΡ€. НазовСм Π΅Π³ΠΎ Compressor.

НачнСм с Π½Π°Ρ‡Π°Π»Π°. ΠŸΠ΅Ρ€Π²Ρ‹ΠΌ Π΄Π΅Π»ΠΎΠΌ пишСм класс 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;
    }
}

Π’Π΅ΠΏΠ΅Ρ€ΡŒ Π΄Π΅Ρ€Π΅Π²Ρ†Π΅:

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

ΠŸΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚Π½Π°Ρ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ:

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;//Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌ ΡƒΠ΄Π°Π»Π΅Π½Π½Ρ‹ΠΉ элСмСнт(элСмСнт с наимСньшСй частотой)
    }
}

Класс, ΡΠΎΠ·Π΄Π°ΡŽΡ‰ΠΈΠΉ Π΄Π΅Ρ€Π΅Π²ΠΎ Π₯Π°Ρ„Ρ„ΠΌΠ°Π½Π°:

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

Класс, содСрТащий ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΊΠΎΠ΄ΠΈΡ€ΡƒΠ΅Ρ‚/Π΄Π΅ΠΊΠΎΠ΄ΠΈΡ€ΡƒΠ΅Ρ‚:

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

Класс, ΠΎΠ±Π»Π΅Π³Ρ‡Π°ΡŽΡ‰ΠΈΠΉ запись Π² Ρ„Π°ΠΉΠ»:

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

Класс, ΠΎΠ±Π»Π΅Π³Ρ‡Π°ΡŽΡ‰ΠΈΠΉ Ρ‡Ρ‚Π΅Π½ΠΈΠ΅ ΠΈΠ· Ρ„Π°ΠΉΠ»Π°:

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

Ну, ΠΈ Π³Π»Π°Π²Π½Ρ‹ΠΉ класс:

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

Π€Π°ΠΉΠ» с инструкциями readme.txt прСдстоит Π²Π°ΠΌ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ самим πŸ™‚

Π—Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅

НавСрноС, это всС Ρ‡Ρ‚ΠΎ я Ρ…ΠΎΡ‚Π΅Π» ΡΠΊΠ°Π·Π°Ρ‚ΡŒ. Если Ρƒ вас Π΅ΡΡ‚ΡŒ Ρ‡Ρ‚ΠΎ ΡΠΊΠ°Π·Π°Ρ‚ΡŒ ΠΏΠΎ ΠΏΠΎΠ²ΠΎΠ΄Ρƒ ΠΌΠΎΠ΅ΠΉ нСкомпСтСнтности ΡƒΠ»ΡƒΡ‡ΡˆΠ΅Π½ΠΈΠΉ Π² ΠΊΠΎΠ΄Π΅, Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΠ΅, Π²ΠΎΠΎΠ±Ρ‰Π΅ любой ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ, Ρ‚ΠΎ смСло ΠΏΠΈΡˆΠΈΡ‚Π΅. Если я Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ нСдообъяснил, Ρ‚ΠΎΠΆΠ΅ ΠΏΠΈΡˆΠΈΡ‚Π΅. Π‘ΡƒΠ΄Ρƒ Ρ€Π°Π΄ ΡƒΡΠ»Ρ‹ΡˆΠ°Ρ‚ΡŒ вас Π² коммСнтариях!

P.S.

Π”Π°-Π΄Π°, я всС Π΅Ρ‰Π΅ здСсь, вСдь я Π½Π΅ Π·Π°Π±Ρ‹Π» ΠΏΡ€ΠΎ коэффициСнт. Для строки s1 кодировочная Ρ‚Π°Π±Π»ΠΈΡ†Π° вСсит 48 Π±Π°ΠΉΡ‚ β€” Π½Π°ΠΌΠ½ΠΎΠ³ΠΎ большС исходного Ρ„Π°ΠΉΠ»Π°, Π΄Π° ΠΈ ΠΏΡ€ΠΎ Π΄ΠΎΠ±Π°Π²ΠΎΡ‡Π½Ρ‹Π΅ Π½ΡƒΠ»ΠΈ Π½Π΅ Π·Π°Π±Ρ‹Π»ΠΈ(количСство Π΄ΠΎΠ±Π°Π²Π»Π΅Π½Π½Ρ‹Ρ… Π½ΡƒΠ»Π΅ΠΉ Ρ€Π°Π²Π½ΠΎ 7)=> коэффициСнт сТатия Π±ΡƒΠ΄Π΅Ρ‚ мСньшС Π΅Π΄ΠΈΠ½ΠΈΡ†Ρ‹: 176/(65 + 48*8 + 7)=0.38. Если Π²Ρ‹ Ρ‚ΠΎΠΆΠ΅ это Π·Π°ΠΌΠ΅Ρ‚ΠΈΠ»ΠΈ, Ρ‚ΠΎ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π½Π΅ ΠΏΠΎ Π»ΠΈΡ†Ρƒ Π²Ρ‹ ΠΌΠΎΠ»ΠΎΠ΄Π΅Ρ†. Π”Π°, эта рСализация Π±ΡƒΠ΄Π΅Ρ‚ ΠΊΡ€Π°ΠΉΠ½Π΅ нСэффСктивной для ΠΌΠ°Π»Ρ‹Ρ… Ρ„Π°ΠΉΠ»ΠΎΠ². Но Ρ‡Ρ‚ΠΎ ΠΆΠ΅ происходит с большими Ρ„Π°ΠΉΠ»Π°ΠΌΠΈ? Π Π°Π·ΠΌΠ΅Ρ€Ρ‹ Ρ„Π°ΠΉΠ»Π° Π½Π°ΠΌΠ½ΠΎΠ³ΠΎ ΠΏΡ€Π΅Π²Ρ‹ΡˆΠ°ΡŽΡ‚ Ρ€Π°Π·ΠΌΠ΅Ρ€ ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²ΠΎΡ‡Π½ΠΎΠΉ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹. Π’ΠΎΡ‚ здСсь-Ρ‚ΠΎ Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ ΠΊΠ°ΠΊ-Π½Π°Π΄ΠΎ! НапримСр, для ΠΌΠΎΠ½ΠΎΠ»ΠΎΠ³Π° Ѐауста Π°Ρ€Ρ…ΠΈΠ²Π°Ρ‚ΠΎΡ€ Π²Ρ‹Π΄Π°Π΅Ρ‚ Ρ€Π΅Π°Π»ΡŒΠ½Ρ‹ΠΉ (Π½Π΅ ΠΈΠ΄Π΅Π°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ) коэффициСнт, Ρ€Π°Π²Π½Ρ‹ΠΉ 1.46 β€” ΠΏΠΎΡ‡Ρ‚ΠΈ Π² ΠΏΠΎΠ»Ρ‚ΠΎΡ€Π° Ρ€Π°Π·Π°! И Π΄Π°, ΠΏΡ€Π΅Π΄ΠΏΠΎΠ»Π°Π³Π°Π»ΠΎΡΡŒ, Ρ‡Ρ‚ΠΎ Ρ„Π°ΠΉΠ» Π±ΡƒΠ΄Π΅Ρ‚ Π½Π° английском языкС.

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com

Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ