W przeciwnym razie będzie sapał i dmuchał i wysadził dom w powietrze!
To było zupełnie nieistotne. To wyzwanie dotyczy kodowania Huffmana . Jego istotą jest częstotliwość znaków w danym tekście wykorzystywana do skrócenia jego reprezentacji. Innymi słowy, powiedzmy, że nasz alfabet ma a
szerokość z
i przestrzeń. To 27 znaków. Każdy z nich może być jednoznacznie zakodowany w zaledwie 5 bitach, ponieważ 5 bitów ma wystarczająco dużo miejsca na 32 znaki. Jednak w wielu sytuacjach (takich jak angielski lub ogólnie języki) niektóre znaki występują częściej niż inne. Możemy użyć mniej bitów dla częstszych znaków i (być może) więcej bitów dla rzadszych znaków. Zrobione dobrze, istnieje ogólna oszczędność liczby bitów, a oryginalny tekst można nadal wyjątkowo odtworzyć.
Weźmy jako przykład „to pytanie dotyczy kodowania huffmana”. Ten tekst ma 37 znaków, czyli 37 * 8 = 296 bitów normalnie, choć tylko 37 * 5 = 185 bitów, jeśli użyjemy tylko 5 bitów na każdy znak. Miej to w pamięci.
Oto (sorta) tabela każdego znaku i ich częstotliwości w tekście, posortowana od najbardziej do najmniejszej (gdzie _ oznacza spację):
_ 5
i 4
n 3
o 3
s 3
t 3
u 3
a 2
f 2
h 2
b 1
c 1
d 1
e 1
g 1
m 1
q 1
Powiązane optymalne kodowanie może być:
_ 101
i 011
n 1100
o 1101
s 1110
t 1111
u 001
a 10011
f 0001
h 0101
b 00000
c 00001
d 01000
e 01001
g 10000
m 10001
q 10010
Od razu powinno być jasne, że będzie to lepsze kodowanie niż tylko użycie 5 bitów na każdy znak. Sprawdźmy jednak, o ile lepiej!
145 bitów , w porównaniu do 185! To oszczędność 40 bitów, czyli nieco ponad 20%! (To oczywiście zakłada, że informacje o strukturze są dostępne do dekodowania.) To kodowanie jest optymalne, ponieważ nie można usunąć więcej bitów przez zmianę reprezentacji dowolnego znaku.
Zadanie
- Napisz program lub funkcję z jednym parametrem, który ...
- Pobiera dane wejściowe ze STDIN (lub odpowiednika) lub jako pojedynczy argument.
- Wypisuje optymalne kodowanie Huffmana, jak wyżej, przy użyciu znaków posortowanych według częstotliwości (kolejność w klasie częstotliwości nie ma znaczenia).
- Możesz założyć, że znaki na wejściu są ograniczone do zakresu ASCII
32..126
plus nowego wiersza. - Możesz założyć, że dane wejściowe nie mają więcej niż 10 000 znaków (najlepiej teoretycznie dane wejściowe powinny być nieograniczone).
- Twój kod powinien zakończyć się dość szybko. Powyższy przykład w najgorszym przypadku nie powinien zająć więcej niż minutę. (Ma to na celu wykluczenie brutalnej siły.)
- Punktacja jest w bajtach.
Przykłady
x
---
x 0
xxxxxxxxx
---
x 0
xxxxxxxxy
---
x 0
y 1 (these may be swapped)
xxxxxyyyz
---
x 0
y 10
z 11
uuvvwwxxyyzz
--- (or)
u 000 000
v 001 001
w 100 010
x 101 011
y 01 10
z 11 11
this question is about huffman coding
---
101
i 011
n 1100
o 1101
s 1110
t 1111
u 001
a 10011
f 0001
h 0101
b 00000
c 00001
d 01000
e 01001
g 10000
m 10001
q 10010
Miłego kodowania!
Zauważ, że to podobne pytanie jest ściśle powiązane, nawet do tego stopnia, że jest to duplikat. Jednak dotychczasowy konsensus w sprawie Meta jest taki, że starszy należy uważać za duplikat tego.
źródło
this question is about huffman coding
policzyłem liczbę bitów jako 145 , a nie 136.Odpowiedzi:
Pyth, 53 bajty
Demonstracja
Oto wersja pokazująca stan wewnętrzny, dzięki czemu można zobaczyć budowane kodowanie:
Demonstracja
Skopiuj wydruk do środowiska z szerszymi liniami, aby uzyskać wyraźniejszy obraz.
źródło
Python 2, 299 bajtów
Oto moja próba odpowiedzi.
Kody Huffmana różnią się od podanych przykładów, ale nadal powinny być optymalne.
źródło
Matlab, 116 bajtów
tabulate
tworzy tabelę częstotliwości.huffmandict
pobiera listę symboli i prawdopodobieństwa dla każdego symbolu i oblicza kod.źródło
Rubin,
189180 bajtówPraca w toku.
To anonimowa funkcja; na przykład przypisz to do czegoś
f
i wywołaj za pomocąktóra zwraca skrót taki jak ten:
źródło
Haskell, 227 bajtów
Przykład użycia:
Jak to działa:
p
wywołań,f
które budują tabelę Huffmana w postaci listy par (znak, kodowanie), np.[ ('a',"0"), ('b',"1") ]
sortuje tabelę według długości kodowania, formatuje każdą parę pod kątem danych wyjściowych i łączy się z nowymi wierszami pomiędzy nimi.f
najpierw sprawdza pojedynczą literę i zwraca odpowiednią tabelę. W przeciwnym razie sortuje ciąg wejściowy i grupuje sekwencje równych znaków (np."ababa"
->["aaa","bb"]
) i odwzorowuje je na pary(sequence , [(char, "")])
, (->[ ("aaa", [('a',"")]), ("bb", [('b', "")])]
. Pierwszy element służy do śledzenia częstotliwości, drugi element jest listą par znaku i to kodujący (który początkowo jest pusta). te wszystkie pojedyncze tabele elementem Huffmana, zgodnie z oczekiwaniamip
, łączy się je przezg
ah
.g
sortuje listę par według długości pierwszego elementu, tj. częstotliwości i wywołańh
.h
łączy tabele Huffmana pierwszych dwóch elementów, łącząc częstotliwości i umieszczając0
(1
) przed każdym elementem pierwszego (drugiego) stołu. Połącz obie tabele. Zadzwońg
ponownie, zatrzymaj się, gdy pozostanie jeden element, wyrzuć część częstotliwości i zwróć pełny stół Huffmana.źródło
K (ngn / k) , 78 bajtów
Wypróbuj online!
zwraca listę ciągów do wydrukowania
h::0#'x
tworzy pustą listę dla każdego znaku (technicznie zmienia kształt każdego znaku na długość 0). tam przechowamy odwrócone kody huffmana. używamy::
zamiast:
do wykonania zadaniah
globalnym, aby było widoczne w podfunkcjach..=x
to lista list - indeksy łańcucha pogrupowane według wartości znakowej(#1_)
jest funkcją, która zwraca prawdę, jeśli długość argumentu wynosi> 1 (technicznie „długość 1 kropli ...”)(#1_){
...}/
oznacza: gdy argument ma długość> 1, nadal stosuj funkcję nawiasu klamrowegox@<#'x
posortuj argument według długości0 2_
pokroić w 2-elementową głowę i ogon{h[x],:!2;y,,,/x}
aktualizacjah
przez dodanie 0 i 1 do wskaźników zawartych w głowie; zwróć ogon z głową jako pojedynczy element(?,/'x,'" ",'|'$h)(?x)?>#'=x
odwróć każdy zh
, sortuj, unikatowy, poprzedzaj odpowiednie znaki i ładnie formatujźródło
JavaScript (ES6) 279
Zasadniczo podstawowy algorytm z Wikipedii. Prawdopodobnie dam radę lepiej.
Bardziej czytelny wewnątrz fragmentu poniżej
źródło