Ou bien il va souffler et souffler et faire sauter votre maison!
C'était complètement hors de propos. Ce défi concerne en fait le codage Huffman . L'essentiel est que la fréquence des caractères dans un texte donné est utilisée pour raccourcir sa représentation. En d'autres termes, disons que notre alphabet est a
traversant z
et spatial. Cela fait 27 caractères. Chacun d'eux peut être codé de manière unique en seulement 5 bits car 5 bits ont suffisamment de place pour 32 caractères. Cependant, dans de nombreuses situations (comme l'anglais ou les langues en général), certains caractères sont plus fréquents que d'autres. Nous pouvons utiliser moins de bits pour les caractères les plus fréquents et (peut-être) plus de bits pour les caractères les moins fréquents. Bien fait, il y a une économie globale sur le nombre de bits et le texte original peut toujours être reconstruit de manière unique.
Prenons "cette question concerne le codage de Huffman" comme exemple. Ce texte est de 37 caractères, ce qui serait normalement 37 * 8 = 296 bits, bien que seulement 37 * 5 = 185 bits si nous n'utilisons que 5 bits pour chaque caractère. Garde cela à l'esprit.
Voici un tableau (sorta) de chaque caractère et de leurs fréquences dans le texte, triés du plus au moins fréquent (où _ représente un espace):
_ 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
Un codage optimal associé pourrait être:
_ 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
Il devrait être immédiatement clair que ce sera un meilleur encodage que d'utiliser simplement 5 bits pour chaque caractère. Voyons à quel point mieux, cependant!
145 bits , contre 185! C'est une économie de 40 bits, soit un peu plus de 20%! (Cela suppose, bien entendu, que des informations sur la structure soient disponibles pour le décodage.) Ce codage est optimal car aucun bit ne peut être supprimé en modifiant la représentation d'un caractère.
La tâche
- Écrivez un programme ou une fonction avec un paramètre qui ...
- Prend l'entrée de STDIN (ou équivalent) ou comme un seul argument.
- Générez un codage Huffman optimal comme ci-dessus avec les caractères triés par fréquence (l'ordre dans une classe de fréquence n'a pas d'importance).
- Vous pouvez supposer que les caractères de l'entrée sont limités à la plage ASCII
32..126
plus une nouvelle ligne. - Vous pouvez supposer que la saisie ne dépasse pas 10 000 caractères (idéalement, en théorie, la saisie doit être illimitée).
- Votre code devrait se terminer assez rapidement. L'exemple donné ci-dessus ne devrait pas prendre plus d'une minute ou plus au pire. (Ceci est destiné à exclure la force brute.)
- La notation est en octets.
Exemples
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
Bon codage!
Notez que cette question similaire est étroitement liée, même au point que celle-ci est un doublon. Cependant, le consensus à ce jour sur Meta est que l'ancien devrait être considéré comme un double de celui-ci.
la source
this question is about huffman coding
, j'ai compté le nombre de bits pour 145 , pas 136.Réponses:
Pyth, 53 octets
Manifestation
Voici une version qui montre l'état interne, afin que vous puissiez voir l'encodage en cours de construction:
Manifestation
Copiez la sortie dans un environnement avec des lignes plus larges pour une image plus claire.
la source
Python 2, 299 octets
Voici ma tentative de réponse.
Les codes Huffman sont différents des exemples donnés, mais devraient toujours être optimaux.
la source
Matlab, 116 octets
tabulate
fait une table de fréquences.huffmandict
prend une liste de symboles et de probabilités pour chaque symbole et calcule le code.la source
Rubis,
189180 octetsTravail en cours.
C'est une fonction anonyme; l'assigner à quelque chose, par exemple
f
, et l'appeler avecqui renvoie un hachage comme ceci:
la source
Haskell, 227 octets
Exemple d'utilisation:
Comment ça fonctionne:
p
les appelsf
qui construisent la table Huffman sous la forme d'une liste de paires (de caractères, d'encodage), par exemple[ ('a',"0"), ('b',"1") ]
, trient la table en fonction de la longueur des encodages, formate chaque paire pour la sortie et joint les sauts de ligne entre les deux.f
vérifie d'abord la casse à une lettre et renvoie le tableau correspondant. Sinon, il trie la chaîne d'entrée et regroupe les séquences de caractères égaux (par exemple"ababa"
->["aaa","bb"]
) et les mappe en paires(sequence , [(char, "")])
, (->[ ("aaa", [('a',"")]), ("bb", [('b', "")])]
. Le premier élément est utilisé pour garder une trace de la fréquence, le deuxième élément est une liste de paires d'un caractère et c'est le codage (qui est initialement vide). Ce sont toutes des tables Huffman à élément unique comme prévu parp
et sont combinées parg
eth
.g
trie la liste des paires sur la longueur du premier élément, c'est-à-dire la fréquence et les appelsh
.h
combine les tables de Huffman des deux premiers éléments, en concaténant les fréquences et en mettant un0
(1
) devant chaque élément de la première (deuxième) table. Concatène les deux tables. Appelez àg
nouveau, arrêtez quand il n'y a plus qu'un élément, jetez la partie fréquence et retournez la table Huffman complète.la source
K (ngn / k) , 78 octets
Essayez-le en ligne!
renvoie une liste de chaînes à imprimer
h::0#'x
crée une liste vide pour chaque caractère (techniquement, il remodèle chaque caractère à la longueur 0). nous y stockerons les codes huffman inversés. nous utilisons::
au lieu de:
pour assignation pour rendreh
global afin qu'il soit visible dans les sous-fonctions..=x
est une liste de listes - les indices de la chaîne regroupés par valeur de caractère(#1_)
est une fonction qui retourne vrai si la longueur de l'argument est> 1 (techniquement "longueur de 1 goutte de ...")(#1_){
...}/
signifie: pendant que l'argument a une longueur> 1, continuez d'appliquer la fonction accoladex@<#'x
trier l'argument par longueur0 2_
le couper en une tête à 2 éléments et une queue{h[x],:!2;y,,,/x}
mettreh
à jour en ajoutant 0 et 1 aux indices contenus dans la tête; retourner la queue avec la tête comme un seul élément(?,/'x,'" ",'|'$h)(?x)?>#'=x
inverser chacunh
, trier, unique, ajouter les caractères correspondants avant et formater correctementla source
JavaScript (ES6) 279
Essentiellement, l'algorithme de base de Wikipedia. Je peux probablement faire mieux.
Plus lisible à l'intérieur de l'extrait ci-dessous
la source