Aller au contenu

Codage de Huffman (décodage à partir de l'arbre)

Présentation rapide

Le codage de Huffman est un codage qui permet de compresser des données. Dans le cas d'un texte, codé en UTF-8, chaque caractère prendra la place de un à 4 octets. Dans le cas du codage de Huffman , plus un caractère est fréquent dans le texte, plus court sera son codage en binaire.

Exemple

Le texte : que voulez vous que je vous dise sera codé par : 01111011101110000011011000011010001111000001101010111011110111011110010110111000001101010111100110110010110. Soit \(107\) bits au lieu de \(256\) avec le codage UTF-8. Le caractère espace ' ' sera codé par 111, tandis que le caractère 'l' sera codé par 1 0000.

Série d'exercices

Cet exercice fait partie d'une série :

Example

Le texte : que voulez vous que je vous dise sera codé par : 01111011101110000011011000011010001111000001101010111011110111011110010110111000001101010111100110110010110. Le caractère espace ' ' sera codé par 111, tandis que le caractère 'l' sera codé par 1 0000.

Les étapes sur un exemple

Prenons pour exemple le texte que voulez vous que je vous dise.

Le nombre d'occurrences de chaque lettre est :

q u e v o l z s j d i
2 5 5 6 3 3 1 1 3 1 1 1
graph TD
    N22(( :32)) --> |0| N20(( :12))
    N22 --> |1| N21(( :20))
    N20 --> |0| N16(( :6))
    N20 --> |1| N17(( :6))
    N16 --> |0| N5(v:3):::feuille
    N16 --> |1| N6(o:3):::feuille
    N17 --> |0| N9(s:3):::feuille
    N17 --> |1| N14(( :3))
    N14 --> |0| N1(i:1):::feuille
    N14 --> |1| N11(q:2):::feuille
    N21 --> |0| N18(( :9))
    N21 --> |1| N19(( :11))
    N18 --> |0| N15(( :4))
    N18 --> |1| N2(u:5):::feuille
    N15 --> |0| N12(( :2))
    N15 --> |1| N13(( :2))
    N12 --> |0| N7(l:1):::feuille
    N12 --> |1| N8(z:1):::feuille
    N13 --> |0| N90(j:1):::feuille
    N13 --> |1| N10(d:1):::feuille
    N19 --> |0| N3(e:5):::feuille
    N19 --> |1| N4(_:6):::feuille
    N5 o-...-o N32[000]:::binaire
    N1 o-..-o N33[0110]:::binaire
    N4 o-...-o N30[111]:::binaire
    N7 o-.-o N31[1 0000]:::binaire
    classDef feuille fill:#F88
    classDef binaire fill:#FF0

Par exemple, l (peu fréquent) sera codé 1 0000 (5 bits) alors que l'espace (très fréquente) sera codée 111 (3 bits).

On obtient le dictionnaire de codage suivant :

🐍 Script Python
{' ': '111', 'e': '110', 'u': '101', 'd': '10011', 'j': '10010', 'z': '10001', 'l': '10000', 'q': '0111', 'i': '0110', 's': '010', 'o': '001', 'v': '000'}

Le texte : «que voulez vous que je vous dise» est alors encodé par : 01111011101110000011011000011010001111000001101010111011110111011110010110111000001101010111100110110010110

On pourra trouver plus d'explications dans l'exercice sur la construction d'un arbre de Huffman.

Décodage⚓︎

Le décodage peut se faire, soit à partir du dictionnaire de codage, mais de façon plus efficace à partir de l'arbre lui-même.

Le codage de Huffman produit un code préfixe, c'est à dire que chaque code n'est pas le début d'un autre.

L'idée est de lire symbole par symbole le texte encodé et de parcourir l'arbre simultanément.

  • On parcourt tout le texte encodé.
  • Si le symbole est 0, alors on descend vers le sous arbre gauche.
  • Si le symbole est 1, alors on descend vers le sous arbre droit.
  • Si on arrive à une feuille, alors le code est terminé et correspond au caractère de la feuille. On ajoute ce caractère au texte décodé. On repart de la racine, pour le prochain caractère
Question 1 : decode_Huffman(texte, arbre)

Créer la fonction decode_Huffman qui prend comme argument un texte codé(chaine de caractère constituée de 0 et de 1) et l'arbre de Huffman, et qui renvoie une chaîne de caractères contenant le texte décodé.

Le décodage du texte se fait en parcourant l'arbre. On s'interdit d'utiliser et/ou de reconstruire le dictionnaire de codage.

Éléments fournis
  • Les étiquettes des nœuds de l'arbre sont des dictionnaire de la forme {"caractere":…, "poids":…}.

  • Une classe Arbre dont un exemple d'utilisation est donné ci-dessous.

    La classe Arbre

    La classe d'arbre proposée dispose de l'interface suivante :

    Constructeur :

    • Arbre(donnee) : renvoie un arbre d'étiquette donnee
    • Arbre(donnee, sous_arbre_gauche, sous_arbre_droit) : renvoie un arbre d'étiquette donnee avec des sous arbres

    Méthodes fournies :

    • donnee() : renvoie l'étiquette de la racine
    • sous_arbre_gauche() : renvoie le sous arbre droit
    • sous_arbre_droit() : renvoie le sous arbre gauche
    • est_feuille()
    Exemple d'utilisation
    🐍 Console Python
    >>> t1 = Arbre("b")
    >>> t2 = Arbre(1, t1, t1)
    >>> t2.donnee()
    1
    >>> t2.sous_arbre_gauche().est_feuille()
    True
    >>> t2.sous_arbre_droit().est_feuille()
    True
    >>> t2.est_feuille()
    False
    
  • Pour vos tests, les fonctions :

    • arbre_Huffman(texte) : renvoie un arbre de Huffman construit à partir du texte passé en paramètre.
    • encode_Huffman(texte) : renvoie le texte encodé avec le codage de Huffman. (Cette fonction utilise la fonction précédente pour générer l'arbre qu'elle utilise pour l'encodage)

    Voir les tests pour un exemple d'utilisation

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier
Évaluations restantes : 10/10

.1280135[tf4)2rjR3,sao iug0xè8m1]P6pnCl7h.e=céy:v9D(Hwq;S/b_dk050$0K0d0o0r0G0n0q0M0G0o0n0n0L010d0r0D010406050n0s0y0y0o0i0O040Y0p0G0s0{0p0E0q020o0y0D0X0q0k0K150i0W0s0K0n050Z12141618100D041w1D051G0Z1G1I1D100$0r0Q0:0=0@0_0I0r0t0I0G1W0I0d0~050+0!0G0K1R0?0^011V1X1Z1X0d1)1+1%0d0!0p0$181(0i1E0d0I0:1b0n0D0o0E0_0h011-1T010e0-0K0E1j0K1%282a2f1/2i1+2l0y2n040a0q0B0i0p0D0p0n0r1e1g0)260i0i0K0M2I1w2p0E1E0Z242U0d2221230$2r0_1Z0E2k2F1%1O1Q0;1.2(0r2*0E1~1P1%0D2N1E2S2U2 11291g2:2g2^0i150G0~0q0z2R330 322q351/37393b0h3e2a3g2S2%013l0o3a040q0l3p2T103s3j0_3v3x0q0f3B3r333t3H3b0b3L3D3N3F3u0p383w3b0C3S3h341S3k3X3m3y0H3$3E3)3G3+3Z3y0x3/3U3;3W3Y3I0R3`3i3|3P040z0u413(2;3}3,0z3d1x3f3T424a440z3o4f3q4h49363?3x0z3A4n2T1F2}1w2.2X0$2#3t0M1~2x0(1P1E2|0K2~3f3L054G0)4O4i2g0%0~0)0e4Q3:4a0V3b4#3{4j0e4Y2O4H0#0U0s0e0e150E4*4V1/0}040T4{4q3k0~0d0K0v550#4S0K513t4~0m3L0q3%3O0~160!2N4;4?4^2a5c3V4~0g0P3S0q5y5h4$365456580)5a5g5i3V0p0~0L5I5B4}0~0c0A5x5z5J430~0i0o0M2?5b4w3y5W4a5L045N5(5A4+5C045l5n4=4@4_5U5y5*5=2^0K0s0$590p0s5Z0E0d5O5;1/5,5.2 5:4|3G5Y5!5$5|6g520_4X040e3X6a6h3u0~0n0O0y1}1+6u6o010p4(042?6D5j0455570K640)5s3|4~5w5(065z6Y6n3t6q0r4!5/5~53046y6A1b5%6f6*0_6d6e3f6!3V0n2d04010u016S4a6U6m6Z5V5P6i04606264662a696)786F5M6K3V0E0~7b634G7e68722g5,0J7u6+0n650n0#5@6P0t0o0s0M0I6:4P7i4~0T0g75776b6p0~0K0.7L3q6=01746W76767!7n7a0p617q65677g6;7i6d7l5X7,7.7d7;7y6?0~7x5(7*6x7B7D0i5m6P0$2C2H7 7#0~7P7R5}7i6$6(7?7T6w7{7c7r7~837@818e7+1u0d0#0e610-6C8u8o7O5v8i6Z846M5E8a4/6R8G6v7w8x5k0D0D2k0$8e7O8V8q7/7s7=7M8o8U8S6E7+0$1f2*7Y4x7N8g0g0c8e6|0~010M165!552N718/5d0~0A7Q7%7(6Y8M7p7}7f7_5+7k7h8o7+5Z5#2*6m7!6q2N0d664`9n6v8 6~97318v04829F9o0~0j0p6J985t8g8%6N5F8Q8^4U6E5u3$0Z5a2U4M2U4B1w0d4D9+2Z2V1}1 2X0o1*4N4A4K1C9X3t2N0y8B0o0%6P0I0l0~1o1q1s1u0q6V311J3g1D0S2a0/0=0q7A1c2I0m0qal0y0N244H0q2K7J0,2*ax1,929q0d0w2N0/4R4H049M9O9$0q8Y380*aq2KaN0E8b1,0d7Barab0N0G0N2w680/0T0E0N0M1u0n0,9 2k0daC0q0d0O8Yam2Y0ga{al1Z0n550q2ka$0/0n0N297;aQ16ar0o0:0IaA1,ay932PaH0K0J0qai0EakaD0?aQ0i0N0na_bibkbmb8b60q0Q0r0)aq1+0qbB120G0+a`8zax1f0M0q0saB4G0E920d0N2l2Ia{a!0sbx0/aE94br0/2Kb40rb6bs1Fag040F0*b7atav2KbW0D1c0/0K4@0r92a;0qaaaCb=bY0ob*b,0r1fbb7Ia;0@1P1u821M4A0*0,0.04.

Remarque

En pratique, le dictionnaire de codage est transmis dans le fichier avec le texte à décoder. Il faut d'abord reconstruire l'arbre, avant de décoder les données.