Алгоритм сТатия Π₯Π°Ρ„Ρ„ΠΌΠ°Π½Π°

Π’ ΠΏΡ€Π΅Π΄Π΄Π²Π΅Ρ€ΠΈΠΈ старта курса «Алгоритмы для Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΎΠ²Β» ΠΏΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²ΠΈΠ»ΠΈ для вас ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄ Π΅Ρ‰Π΅ ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΠΏΠΎΠ»Π΅Π·Π½ΠΎΠ³ΠΎ ΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»Π°.

ΠšΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π₯Π°Ρ„Ρ„ΠΌΠ°Π½Π° – это Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌ сТатия Π΄Π°Π½Π½Ρ‹Ρ…, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Ρ„ΠΎΡ€ΠΌΡƒΠ»ΠΈΡ€ΡƒΠ΅Ρ‚ ΠΎΡΠ½ΠΎΠ²Π½ΡƒΡŽ идСю сТатия Ρ„Π°ΠΉΠ»ΠΎΠ². Π’ этой ΡΡ‚Π°Ρ‚ΡŒΠ΅ ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ Π³ΠΎΠ²ΠΎΡ€ΠΈΡ‚ΡŒ ΠΎ ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠΈ фиксированной ΠΈ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ Π΄Π»ΠΈΠ½Ρ‹, ΡƒΠ½ΠΈΠΊΠ°Π»ΡŒΠ½ΠΎ Π΄Π΅ΠΊΠΎΠ΄ΠΈΡ€ΡƒΠ΅ΠΌΡ‹Ρ… ΠΊΠΎΠ΄Π°Ρ…, прСфиксных ΠΏΡ€Π°Π²ΠΈΠ»Π°Ρ… ΠΈ построСнии Π΄Π΅Ρ€Π΅Π²Π° Π₯Π°Ρ„Ρ„ΠΌΠ°Π½Π°.

ΠœΡ‹ Π·Π½Π°Π΅ΠΌ, Ρ‡Ρ‚ΠΎ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ символ хранится Π² Π²ΠΈΠ΄Π΅ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ ΠΈΠ· 0 ΠΈ 1 ΠΈ Π·Π°Π½ΠΈΠΌΠ°Π΅Ρ‚ 8 Π±ΠΈΡ‚. Π­Ρ‚ΠΎ называСтся ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ фиксированной Π΄Π»ΠΈΠ½Ρ‹, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ символ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²ΠΎΠ΅ фиксированноС количСство Π±ΠΈΡ‚ΠΎΠ² для хранСния.

Допустим, Π΄Π°Π½ тСкст. Каким ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΡΠΎΠΊΡ€Π°Ρ‚ΠΈΡ‚ΡŒ количСство мСста, Ρ‚Ρ€Π΅Π±ΡƒΠ΅ΠΌΠΎΠ³ΠΎ для хранСния ΠΎΠ΄Π½ΠΎΠ³ΠΎ символа?

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

Как, зная ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ Π±ΠΈΡ‚ΠΎΠ², Π΄Π΅ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π΅Π΅ ΠΎΠ΄Π½ΠΎΠ·Π½Π°Ρ‡Π½ΠΎ?

Рассмотрим строку Β«aabacdabΒ». Π’ Π½Π΅ΠΉ 8 символов, ΠΈ ΠΏΡ€ΠΈ ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠΈ фиксированной Π΄Π»ΠΈΠ½Ρ‹ для Π΅Π΅ хранСния понадобится 64 Π±ΠΈΡ‚Π°. Π—Π°ΠΌΠ΅Ρ‚ΠΈΠΌ, Ρ‡Ρ‚ΠΎ частота символов Β«aΒ», Β«bΒ», Β«cΒ» ΠΈ Β«dΒ» равняСтся 4, 2, 1, 1 соотвСтствСнно. Π”Π°Π²Π°ΠΉΡ‚Π΅ ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠ΅ΠΌ ΠΏΡ€Π΅Π΄ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ Β«aabacdabΒ» мСньшим количСством Π±ΠΈΡ‚ΠΎΠ², ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ Ρ‚ΠΎΡ‚ Ρ„Π°ΠΊΡ‚, Ρ‡Ρ‚ΠΎ Β«aΒ» встрСчаСтся Ρ‡Π°Ρ‰Π΅, Ρ‡Π΅ΠΌ Β«bΒ», Π° Β«bΒ» встрСчаСтся Ρ‡Π°Ρ‰Π΅, Ρ‡Π΅ΠΌ Β«cΒ» ΠΈ Β«dΒ». НачнСм ΠΌΡ‹ с Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎ Π·Π°ΠΊΠΎΠ΄ΠΈΡ€ΡƒΠ΅ΠΌ Β«aΒ» с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΎΠ΄Π½ΠΎΠ³ΠΎ Π±ΠΈΡ‚Π°, Ρ€Π°Π²Π½ΠΎΠ³ΠΎ 0, Β«bΒ» ΠΌΡ‹ присвоим Π΄Π²ΡƒΡ…Π±ΠΈΡ‚Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ 11, Π° с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Ρ‚Ρ€Π΅Ρ… Π±ΠΈΡ‚ΠΎΠ² 100 ΠΈ 011 Π·Π°ΠΊΠΎΠ΄ΠΈΡ€ΡƒΠ΅ΠΌ Β«cΒ» ΠΈ Β«dΒ».

Π’ ΠΈΡ‚ΠΎΠ³Π΅ Ρƒ нас получится:

a
0

b
11

c
100

d
011

Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ строку Β«aabacdabΒ» ΠΌΡ‹ Π·Π°ΠΊΠΎΠ΄ΠΈΡ€ΡƒΠ΅ΠΌ ΠΊΠ°ΠΊ 00110100011011 (0|0|11|0|100|011|0|11), ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ ΠΊΠΎΠ΄Ρ‹, прСдставлСнныС Π²Ρ‹ΡˆΠ΅. Однако основная ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ° Π±ΡƒΠ΄Π΅Ρ‚ Π² Π΄Π΅ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠΈ. Когда ΠΌΡ‹ ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠ΅ΠΌ Π΄Π΅ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ строку 00110100011011, Ρƒ нас получится Π½Π΅ΠΎΠ΄Π½ΠΎΠ·Π½Π°Ρ‡Π½Ρ‹ΠΉ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ Π΅Π΅ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΡ€Π΅Π΄ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ ΠΊΠ°ΠΊ:

0|011|0|100|011|0|11    adacdab
0|0|11|0|100|0|11|011   aabacabd
0|011|0|100|0|11|0|11   adacabab 

…
ΠΈ Ρ‚.Π΄.

Π§Ρ‚ΠΎΠ±Ρ‹ ΠΈΠ·Π±Π΅ΠΆΠ°Ρ‚ΡŒ этой нСоднозначности, ΠΌΡ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π³Π°Ρ€Π°Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ, Ρ‡Ρ‚ΠΎ нашС ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ удовлСтворяСт Ρ‚Π°ΠΊΠΎΠΌΡƒ ΠΏΠΎΠ½ΡΡ‚ΠΈΡŽ, ΠΊΠ°ΠΊ прСфиксноС ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π² свою ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ ΠΏΠΎΠ΄Ρ€Π°Π·ΡƒΠΌΠ΅Π²Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ ΠΊΠΎΠ΄Ρ‹ ΠΌΠΎΠΆΠ½ΠΎ Π΄Π΅ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ всСго ΠΎΠ΄Π½ΠΈΠΌ ΡƒΠ½ΠΈΠΊΠ°Π»ΡŒΠ½Ρ‹ΠΌ способом. ΠŸΡ€Π΅Ρ„ΠΈΠΊΡΠ½ΠΎΠ΅ ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ Π³Π°Ρ€Π°Π½Ρ‚ΠΈΡ€ΡƒΠ΅Ρ‚, Ρ‡Ρ‚ΠΎ Π½ΠΈ ΠΎΠ΄ΠΈΠ½ ΠΊΠΎΠ΄ Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ прСфиксом Π΄Ρ€ΡƒΠ³ΠΎΠ³ΠΎ. Под ΠΊΠΎΠ΄ΠΎΠΌ ΠΌΡ‹ ΠΏΠΎΠ΄Ρ€Π°Π·ΡƒΠΌΠ΅Π²Π°Π΅ΠΌ Π±ΠΈΡ‚Ρ‹, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡ‹Π΅ для прСдставлСния ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠ³ΠΎ символа. Π’ ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½ΠΎΠΌ Π²Ρ‹ΡˆΠ΅ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ 0 – это прСфикс 011, Ρ‡Ρ‚ΠΎ Π½Π°Ρ€ΡƒΡˆΠ°Π΅Ρ‚ прСфиксноС ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ. Π˜Ρ‚Π°ΠΊ, Ссли наши ΠΊΠΎΠ΄Ρ‹ ΡƒΠ΄ΠΎΠ²Π»Π΅Ρ‚Π²ΠΎΡ€ΡΡŽΡ‚ прСфиксному ΠΏΡ€Π°Π²ΠΈΠ»Ρƒ, Ρ‚ΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΠΎΠ΄Π½ΠΎΠ·Π½Π°Ρ‡Π½ΠΎ провСсти Π΄Π΅ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ (ΠΈ Π½Π°ΠΎΠ±ΠΎΡ€ΠΎΡ‚).

Π”Π°Π²Π°ΠΉΡ‚Π΅ пСрСсмотрим ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Π²Ρ‹ΡˆΠ΅. На этот Ρ€Π°Π· ΠΌΡ‹ Π½Π°Π·Π½Π°Ρ‡ΠΈΠΌ для символов Β«aΒ», Β«bΒ», Β«cΒ» ΠΈ Β«dΒ» ΠΊΠΎΠ΄Ρ‹, ΡƒΠ΄ΠΎΠ²Π»Π΅Ρ‚Π²ΠΎΡ€ΡΡŽΡ‰ΠΈΠ΅ прСфиксному ΠΏΡ€Π°Π²ΠΈΠ»Ρƒ.

a
0

b
10

c
110

d
111

Π‘ использованиСм Ρ‚Π°ΠΊΠΎΠ³ΠΎ кодирования, строка Β«aabacdabΒ» Π±ΡƒΠ΄Π΅Ρ‚ Π·Π°ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Π½Π° ΠΊΠ°ΠΊ 00100100011010 (0|0|10|0|100|011|0|10). А Π²ΠΎΡ‚ 00100100011010 ΠΌΡ‹ ΡƒΠΆΠ΅ смоТСм ΠΎΠ΄Π½ΠΎΠ·Π½Π°Ρ‡Π½ΠΎ Π΄Π΅ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΈ Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒΡΡ ΠΊ нашСй исходной строкС Β«aabacdabΒ».

ΠšΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π₯Π°Ρ„Ρ„ΠΌΠ°Π½Π°

Π’Π΅ΠΏΠ΅Ρ€ΡŒ, ΠΊΠΎΠ³Π΄Π° ΠΌΡ‹ Ρ€Π°Π·ΠΎΠ±Ρ€Π°Π»ΠΈΡΡŒ с ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ Π΄Π»ΠΈΠ½Ρ‹ ΠΈ прСфиксным ΠΏΡ€Π°Π²ΠΈΠ»ΠΎΠΌ, Π΄Π°Π²Π°ΠΉΡ‚Π΅ ΠΏΠΎΠ³ΠΎΠ²ΠΎΡ€ΠΈΠΌ ΠΎ ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠΈ Π₯Π°Ρ„Ρ„ΠΌΠ°Π½Π°.

ΠœΠ΅Ρ‚ΠΎΠ΄ основываСтся Π½Π° создании Π±ΠΈΠ½Π°Ρ€Π½Ρ‹Ρ… Π΄Π΅Ρ€Π΅Π²ΡŒΠ΅Π². Π’ Π½Π΅ΠΌ ΡƒΠ·Π΅Π» ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ Π»ΠΈΠ±ΠΎ ΠΊΠΎΠ½Π΅Ρ‡Π½Ρ‹ΠΌ, Π»ΠΈΠ±ΠΎ Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½ΠΈΠΌ. Π˜Π·Π½Π°Ρ‡Π°Π»ΡŒΠ½ΠΎ всС ΡƒΠ·Π»Ρ‹ ΡΡ‡ΠΈΡ‚Π°ΡŽΡ‚ΡΡ Π»ΠΈΡΡ‚ΡŒΡΠΌΠΈ (ΠΊΠΎΠ½Π΅Ρ‡Π½Ρ‹ΠΌΠΈ), ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΡ€Π΅Π΄ΡΡ‚Π°Π²Π»ΡΡŽΡ‚ сам символ ΠΈ Π΅Π³ΠΎ вСс (Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ частоту появлСния). Π’Π½ΡƒΡ‚Ρ€Π΅Π½Π½ΠΈΠ΅ ΡƒΠ·Π»Ρ‹ содСрТат вСс символа ΠΈ ΡΡΡ‹Π»Π°ΡŽΡ‚ΡΡ Π½Π° Π΄Π²Π° ΡƒΠ·Π»Π°-наслСдника. По ΠΎΠ±Ρ‰Π΅ΠΌΡƒ соглашСнию, Π±ΠΈΡ‚ Β«0Β» прСдставляСт слСдованиС ΠΏΠΎ Π»Π΅Π²ΠΎΠΉ Π²Π΅Ρ‚Π²ΠΈ, Π° Β«1Β» β€” ΠΏΠΎ ΠΏΡ€Π°Π²ΠΎΠΉ. Π’ ΠΏΠΎΠ»Π½ΠΎΠΌ Π΄Π΅Ρ€Π΅Π²Π΅ N Π»ΠΈΡΡ‚ΡŒΠ΅Π² ΠΈ N-1 Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½ΠΈΡ… ΡƒΠ·Π»ΠΎΠ². РСкомСндуСтся, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΈ построСнии Π΄Π΅Ρ€Π΅Π²Π° Π₯Π°Ρ„Ρ„ΠΌΠ°Π½Π° ΠΎΡ‚Π±Ρ€Π°ΡΡ‹Π²Π°Π»ΠΈΡΡŒ Π½Π΅ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡ‹Π΅ символы для получСния ΠΊΠΎΠ΄ΠΎΠ² ΠΎΠΏΡ‚ΠΈΠΌΠ°Π»ΡŒΠ½ΠΎΠΉ Π΄Π»ΠΈΠ½Ρ‹.

ΠœΡ‹ Π±ΡƒΠ΄Π΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ с ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚Π°ΠΌΠΈ для построСния Π΄Π΅Ρ€Π΅Π²Π° Π₯Π°Ρ„Ρ„ΠΌΠ°Π½Π°, Π³Π΄Π΅ ΡƒΠ·Π»Ρƒ с наимСньшСй частотой Π±ΡƒΠ΄Π΅Ρ‚ присвоСн Π²Ρ‹ΡΡˆΠΈΠΉ ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚. НиТС описаны шаги построСния:

  1. Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ ΡƒΠ·Π΅Π»-лист для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ символа ΠΈ Π΄ΠΎΠ±Π°Π²ΡŒΡ‚Π΅ ΠΈΡ… Π² ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ с ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚Π°ΠΌΠΈ.
  2. Пока Π² ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ большС ΠΎΠ΄Π½ΠΎΠ³ΠΎ листа Π΄Π΅Π»Π°Π΅ΠΌ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π΅:
    • Π£Π΄Π°Π»ΠΈΡ‚Π΅ Π΄Π²Π° ΡƒΠ·Π»Π° с Π½Π°ΠΈΠ²Ρ‹ΡΡˆΠΈΠΌ ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚ΠΎΠΌ (с самой Π½ΠΈΠ·ΠΊΠΎΠΉ частотой) ΠΈΠ· ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ;
    • Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ Π½ΠΎΠ²Ρ‹ΠΉ Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½ΠΈΠΉ ΡƒΠ·Π΅Π», Π³Π΄Π΅ эти Π΄Π²Π° ΡƒΠ·Π»Π° Π±ΡƒΠ΄ΡƒΡ‚ наслСдниками, Π° частота появлСния Π±ΡƒΠ΄Π΅Ρ‚ Ρ€Π°Π²Π½Π° суммС частот этих Π΄Π²ΡƒΡ… ΡƒΠ·Π»ΠΎΠ².
    • Π”ΠΎΠ±Π°Π²ΡŒΡ‚Π΅ Π½ΠΎΠ²Ρ‹ΠΉ ΡƒΠ·Π΅Π» Π² ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚ΠΎΠ².
  3. ЕдинствСнный ΠΎΡΡ‚Π°Π²ΡˆΠΈΠΉΡΡ ΡƒΠ·Π΅Π» Π±ΡƒΠ΄Π΅Ρ‚ ΠΊΠΎΡ€Π½Π΅Π²Ρ‹ΠΌ, Π½Π° этом построСниС Π΄Π΅Ρ€Π΅Π²Π° закончится.

ΠŸΡ€Π΅Π΄ΡΡ‚Π°Π²ΠΈΠΌ, Ρ‡Ρ‚ΠΎ Ρƒ нас Π΅ΡΡ‚ΡŒ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ тСкст, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ состоит Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΈΠ· символов Β«aΒ», Β«bΒ», Β«cΒ», Β«dΒ» ΠΈ Β«eΒ», Π° частоты ΠΈΡ… появлСния Ρ€Π°Π²Π½Ρ‹ 15, 7, 6, 6 ΠΈ 5 соотвСтствСнно. НиТС ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Ρ‹ ΠΈΠ»Π»ΡŽΡΡ‚Ρ€Π°Ρ†ΠΈΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΎΡ‚Ρ€Π°ΠΆΠ°ΡŽΡ‚ шаги Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΠ°.

Алгоритм сТатия Π₯Π°Ρ„Ρ„ΠΌΠ°Π½Π°

Алгоритм сТатия Π₯Π°Ρ„Ρ„ΠΌΠ°Π½Π°

Алгоритм сТатия Π₯Π°Ρ„Ρ„ΠΌΠ°Π½Π°

Алгоритм сТатия Π₯Π°Ρ„Ρ„ΠΌΠ°Π½Π°

Алгоритм сТатия Π₯Π°Ρ„Ρ„ΠΌΠ°Π½Π°

ΠŸΡƒΡ‚ΡŒ ΠΎΡ‚ корня Π΄ΠΎ любого ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎΠ³ΠΎ ΡƒΠ·Π»Π° Π±ΡƒΠ΄Π΅Ρ‚ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ ΠΎΠΏΡ‚ΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ прСфиксный ΠΊΠΎΠ΄ (Ρ‚Π°ΠΊΠΆΠ΅ извСстный, ΠΊΠ°ΠΊ ΠΊΠΎΠ΄ Π₯Π°Ρ„Ρ„ΠΌΠ°Π½Π°), ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΉ символу, связанному с этим ΠΊΠΎΠ½Π΅Ρ‡Π½Ρ‹ΠΌ ΡƒΠ·Π»ΠΎΠΌ.

Алгоритм сТатия Π₯Π°Ρ„Ρ„ΠΌΠ°Π½Π°
Π”Π΅Ρ€Π΅Π²ΠΎ Π₯Π°Ρ„Ρ„ΠΌΠ°Π½Π°

НиТС Π²Ρ‹ Π½Π°ΠΉΠ΄Π΅Ρ‚Π΅ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΡŽ Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΠ° сТатия Π₯Π°Ρ„Ρ„ΠΌΠ°Π½Π° Π½Π° языках C++ ΠΈ Java:

#include <iostream>
#include <string>
#include <queue>
#include <unordered_map>
using namespace std;

// A Tree node
struct Node
{
	char ch;
	int freq;
	Node *left, *right;
};

// Function to allocate a new tree node
Node* getNode(char ch, int freq, Node* left, Node* right)
{
	Node* node = new Node();

	node->ch = ch;
	node->freq = freq;
	node->left = left;
	node->right = right;

	return node;
}

// Comparison object to be used to order the heap
struct comp
{
	bool operator()(Node* l, Node* r)
	{
		// highest priority item has lowest frequency
		return l->freq > r->freq;
	}
};

// traverse the Huffman Tree and store Huffman Codes
// in a map.
void encode(Node* root, string str,
			unordered_map<char, string> &huffmanCode)
{
	if (root == nullptr)
		return;

	// found a leaf node
	if (!root->left && !root->right) {
		huffmanCode[root->ch] = str;
	}

	encode(root->left, str + "0", huffmanCode);
	encode(root->right, str + "1", huffmanCode);
}

// traverse the Huffman Tree and decode the encoded string
void decode(Node* root, int &index, string str)
{
	if (root == nullptr) {
		return;
	}

	// found a leaf node
	if (!root->left && !root->right)
	{
		cout << root->ch;
		return;
	}

	index++;

	if (str[index] =='0')
		decode(root->left, index, str);
	else
		decode(root->right, index, str);
}

// Builds Huffman Tree and decode given input text
void buildHuffmanTree(string text)
{
	// count frequency of appearance of each character
	// and store it in a map
	unordered_map<char, int> freq;
	for (char ch: text) {
		freq[ch]++;
	}

	// Create a priority queue to store live nodes of
	// Huffman tree;
	priority_queue<Node*, vector<Node*>, comp> pq;

	// Create a leaf node for each characterΒ and add it
	// to the priority queue.
	for (auto pair: freq) {
		pq.push(getNode(pair.first, pair.second, nullptr, nullptr));
	}

	// do till there is more than one node in the queue
	while (pq.size() != 1)
	{
		// Remove the two nodes of highest priority
		// (lowest frequency) from the queue
		Node *left = pq.top(); pq.pop();
		Node *right = pq.top();	pq.pop();

		// Create a new internal node with these two nodes
		// as children and with frequency equal to the sum
		// of the two nodes' frequencies. Add the new node
		// to the priority queue.
		int sum = left->freq + right->freq;
		pq.push(getNode('', sum, left, right));
	}

	// root stores pointer to root of Huffman Tree
	Node* root = pq.top();

	// traverse the Huffman Tree and store Huffman Codes
	// in a map. Also prints them
	unordered_map<char, string> huffmanCode;
	encode(root, "", huffmanCode);

	cout << "Huffman Codes are :n" << 'n';
	for (auto pair: huffmanCode) {
		cout << pair.first << " " << pair.second << 'n';
	}

	cout << "nOriginal string was :n" << text << 'n';

	// print encoded string
	string str = "";
	for (char ch: text) {
		str += huffmanCode[ch];
	}

	cout << "nEncoded string is :n" << str << 'n';

	// traverse the Huffman Tree again and this time
	// decode the encoded string
	int index = -1;
	cout << "nDecoded string is: n";
	while (index < (int)str.size() - 2) {
		decode(root, index, str);
	}
}

// Huffman coding algorithm
int main()
{
	string text = "Huffman coding is a data compression algorithm.";

	buildHuffmanTree(text);

	return 0;
}

import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;

// A Tree node
class Node
{
	char ch;
	int freq;
	Node left = null, right = null;

	Node(char ch, int freq)
	{
		this.ch = ch;
		this.freq = freq;
	}

	public Node(char ch, int freq, Node left, Node right) {
		this.ch = ch;
		this.freq = freq;
		this.left = left;
		this.right = right;
	}
};

class Huffman
{
	// traverse the Huffman Tree and store Huffman Codes
	// in a map.
	public static void encode(Node root, String str,
							  Map<Character, String> huffmanCode)
	{
		if (root == null)
			return;

		// found a leaf node
		if (root.left == null && root.right == null) {
			huffmanCode.put(root.ch, str);
		}


		encode(root.left, str + "0", huffmanCode);
		encode(root.right, str + "1", huffmanCode);
	}

	// traverse the Huffman Tree and decode the encoded string
	public static int decode(Node root, int index, StringBuilder sb)
	{
		if (root == null)
			return index;

		// found a leaf node
		if (root.left == null && root.right == null)
		{
			System.out.print(root.ch);
			return index;
		}

		index++;

		if (sb.charAt(index) == '0')
			index = decode(root.left, index, sb);
		else
			index = decode(root.right, index, sb);

		return index;
	}

	// Builds Huffman Tree and huffmanCode and decode given input text
	public static void buildHuffmanTree(String text)
	{
		// count frequency of appearance of each character
		// and store it in a map
		Map<Character, Integer> freq = new HashMap<>();
		for (int i = 0 ; i < text.length(); i++) {
			if (!freq.containsKey(text.charAt(i))) {
				freq.put(text.charAt(i), 0);
			}
			freq.put(text.charAt(i), freq.get(text.charAt(i)) + 1);
		}

		// Create a priority queue to store live nodes of Huffman tree
		// Notice that highest priority item has lowest frequency
		PriorityQueue<Node> pq = new PriorityQueue<>(
										(l, r) -> l.freq - r.freq);

		// Create a leaf node for each characterΒ and add it
		// to the priority queue.
		for (Map.Entry<Character, Integer> entry : freq.entrySet()) {
			pq.add(new Node(entry.getKey(), entry.getValue()));
		}

		// do till there is more than one node in the queue
		while (pq.size() != 1)
		{
			// Remove the two nodes of highest priority
			// (lowest frequency) from the queue
			Node left = pq.poll();
			Node right = pq.poll();

			// Create a new internal node with these two nodes as children 
			// and with frequency equal to the sum of the two nodes
			// frequencies. Add the new node to the priority queue.
			int sum = left.freq + right.freq;
			pq.add(new Node('', sum, left, right));
		}

		// root stores pointer to root of Huffman Tree
		Node root = pq.peek();

		// traverse the Huffman tree and store the Huffman codes in a map
		Map<Character, String> huffmanCode = new HashMap<>();
		encode(root, "", huffmanCode);

		// print the Huffman codes
		System.out.println("Huffman Codes are :n");
		for (Map.Entry<Character, String> entry : huffmanCode.entrySet()) {
			System.out.println(entry.getKey() + " " + entry.getValue());
		}

		System.out.println("nOriginal string was :n" + text);

		// print encoded string
		StringBuilder sb = new StringBuilder();
		for (int i = 0 ; i < text.length(); i++) {
			sb.append(huffmanCode.get(text.charAt(i)));
		}

		System.out.println("nEncoded string is :n" + sb);

		// traverse the Huffman Tree again and this time
		// decode the encoded string
		int index = -1;
		System.out.println("nDecoded string is: n");
		while (index < sb.length() - 2) {
			index = decode(root, index, sb);
		}
	}

	public static void main(String[] args)
	{
		String text = "Huffman coding is a data compression algorithm.";

		buildHuffmanTree(text);
	}
}

ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΠ΅: ΠΏΠ°ΠΌΡΡ‚ΡŒ, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΠ°Ρ Π²Ρ…ΠΎΠ΄Π½ΠΎΠΉ строкой, составляСт 47 * 8 = 376 Π±ΠΈΡ‚, Π° закодированная строка Π·Π°Π½ΠΈΠΌΠ°Π΅Ρ‚ всСго 194 Π±ΠΈΡ‚Π°, Ρ‚.Π΅. Π΄Π°Π½Π½Ρ‹Π΅ ΡΠΆΠΈΠΌΠ°ΡŽΡ‚ΡΡ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π½ΠΎ Π½Π° 48%. Π’ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ΅ Π½Π° Π‘++ Π²Ρ‹ΡˆΠ΅ ΠΌΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ класс string для хранСния Π·Π°ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎΠΉ строки, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ Ρ‡ΠΈΡ‚Π°Π΅ΠΌΠΎΠΉ.

ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ эффСктивныС структуры Π΄Π°Π½Π½Ρ‹Ρ… ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚ΠΎΠ² Ρ‚Ρ€Π΅Π±ΡƒΡŽΡ‚ Π½Π° вставку O(log(N)) Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ, Π° Π² ΠΏΠΎΠ»Π½ΠΎΠΌ Π±ΠΈΠ½Π°Ρ€Π½ΠΎΠΌ Π΄Π΅Ρ€Π΅Π²Π΅ с N Π»ΠΈΡΡ‚ΡŒΡΠΌΠΈ присутствуСт 2N-1 ΡƒΠ·Π»ΠΎΠ², ΠΈ Π΄Π΅Ρ€Π΅Π²ΠΎ Π₯Π°Ρ„Ρ„ΠΌΠ°Π½Π° – это ΠΏΠΎΠ»Π½ΠΎΠ΅ Π±ΠΈΠ½Π°Ρ€Π½ΠΎΠ΅ Π΄Π΅Ρ€Π΅Π²ΠΎ, Ρ‚ΠΎ Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ Π·Π° O(Nlog(N)) Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ, Π³Π΄Π΅ N – количСство символов.

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊΠΈ:

en.wikipedia.org/wiki/Huffman_coding
en.wikipedia.org/wiki/Variable-length_code
www.youtube.com/watch?v=5wRPin4oxCo

Π£Π·Π½Π°Ρ‚ΡŒ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½Π΅Π΅ ΠΎ курсС.

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