Aller au contenu

Codage de Huffman (encodage du texte)

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 :

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

L'arbre de Huffman est un arbre construit progressivement à partir des feuilles.

On commence par créer des nœuds pour tous les caractères. La donnée associée à chaque nœud est un caractère et son poids qui est son nombre d'occurrences.

graph TD
    N7(l:1):::feuille
    N8(z:1):::feuille
    N90(j:1):::feuille
    N10(d:1):::feuille
    N1(i:1):::feuille
    N11(q:2):::feuille
    N5(v:3):::feuille
    N6(o:3):::feuille
    N9(s:3):::feuille
    N2(u:5):::feuille
    N3(e:5):::feuille
    N4(_:6):::feuille
    classDef feuille fill:#F88
graph TD
    N22(( :32)) --> N20(( :12))
    N22 --> N21(( :20))
    N20 --> N16(( :6))
    N20 --> N17(( :6))
    N16 --> N5(v:3):::feuille
    N16 --> N6(o:3):::feuille
    N17 --> N9(s:3):::feuille
    N17 --> N14(( :3))
    N14 --> N1(i:1):::feuille
    N14 --> N11(q:2):::feuille
    N21 --> N18(( :9))
    N18 --> N15(( :4))
    N18 --> N2(u:5):::feuille
    N15 --> N12(( :2))
    N15 --> N13(( :2))
    N12 --> N7(l:1):::feuille
    N12 --> N8(z:1):::feuille
    N13 --> N90(j:1):::feuille
    N13 --> N10(d:1):::feuille
    N21 --> N19( :11)
    N19 --> N3(e:5):::feuille
    N19 --> N4(_:6):::feuille
    classDef feuille fill:#F88

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

Encodage⚓︎

Une fois l'arbre construit, il faut procéder à l'encodage du texte. On va créer un dictionnaire, dont les clés seront les caractères et les valeurs associées, le codage binaire du caractère en utilisant l'arbre construit.

La convention utilisée ici sera la suivante :

Dans l'arbre chaque embranchement à gauche correspond à 0 et chaque embranchement à droite correspond à 1.

Exemple d'arbre et de codes

On obtient l'arbre suivant :

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
    classDef feuille fill:#F88

Plus un symbole est fréquent, plus il est proche de la racine.

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).

Note

Toutes les fonctions crées dans des questions, sont utilisables dans les questions suivantes.

Question 1 : lettre_binaire(arbre)

Principe : on parcourt récursivement l'arbre en profondeur. À chaque fois qu'on arrive sur un nœud,

  • si c'est une feuille, on met à jour le dictionnaire de codage
  • sinon on appelle récursivement le parcours en mettant à jour l'argument code en fonction du sous arbre gauche ou droit.

Compléter la fonction lettre_binaire qui prend comme paramètre un arbre de Huffman et qui renvoie un dictionnaire avec comme clé, les caractères et comme valeurs associées, le codage binaire du caractère.

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

###(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

.339.128013bàuS[,3_4l.(wn/R8p)aPk0;:Fhors1v7c25qm6gyd]i{9eN}Uft =+050R0W0#0v0T0l0F0$0J0l0v0F0F0%010#0T0t010406050F0e0N0N0v0E0Q040f0D0l0e0|0D0p0$020v0N0t0z0$0r0W160E0M0e0W0F050q13151719110t041x1E051H0q1H1J1E110R0T0H0;0?0^0`0C0T0P0C0l1X0C0#0 050,0c0l0W1S0@0_011W1Y1!1Y0#1*1,1(0#0c0D0R191)0E1F0#0C0;1c0F0t0v0p0`0K011.1U010!0.0W0p1k0W1(292b2g1:2j1,2m0N2o040b0$0w0E0D0t0D0F0T1f1h0*270E0E0W0J2J1x2q0p1F0q252V0#2322240R2s0`1!0p2l2G1(1P1R0=1/2)0T2+0p1 1Q1(0t2O1F2T2V30122a1h2;2h2_0E160l0 0$0G2S3410332r361:383a3c0K3f2b3h2T2(013m0v3b040$0i3q2U113t3k0`3w3y0$0k3C3s343u3I3c0L3M3E3O3G3v0D393x3c0O3T3i351T3l3Y3n3z0I3%3F3*3H3,3!3z0s3:3V3=3X3Z3J0V3{3j3}3Q040G0y423)2=3~3-0G3e1y3g3U434b450G3p4g3r4i4a373@3y0G3B4o3D3(3P4t0 0G3L4x3N4j4s3 4C3S4F1G2~1x2/2Y0R2$3u0J1 2y0)1Q1F2}0W2 3g3M054V0*4%4H1:0x0 0*0!4)3;4b0o3c4@3|4k0!0 1,1_2O0j0c2@0-2O4|4.0`0~040n594r3l0 170c584M4^2h5c0h3M0$4z3W0p0 4+0v0P0W5f3u0D0 0%5B3W0F2e0401015G3}5p5r5t445w1 5y1v0j3x0t0C0v0c0+5r5s5n1:5D045F5m4}2h0x0J0 0X1g5A5/5a015c0u0A3T0$625)5:4/0 0T4?4F645|5v045x5z0F5X0l5Z5#5%6a6b5g0`5,0%5.306o3u5=5@5_5Q5*6q4`042b0R6A653H5i0E5k5`326B015,0m5N4k0 1v0#0j0!0W0e0.1,6T5o0 0n5 61636.5R6U6e170v2Q0W5l6u6:2h6r6H6c6K6M6(5+0 6S5{6p3v4;1g2+6N4(6P5c6+0g730`5I0 010J6?6^2O5M773u5c0S6-6.626|66042O0#0e0E0p6 785c0U7j796=0E6@0#6_7d3r7A5b0 607t5H0G0 000y007M5c0Y7x6v3W4:04687I3P5T0R5V6h5Y5!5$0#5(7V6Q5E6t3g7.3}6x045^2+7*7X7-6/6P6d6f5W7|6l7 6n816~7Z5O0 0U7,4F068f6I017:7=6a816d5j6`7e8y6R7M6d6W6Y6!6$7T2U817g6,8v7y638D5w7p7R8G3r864b8p6{8g718$8R6P8J8q6;0R7b0W8Q4-7J6*0u7i8=2h7l5K7o7P7q2o8c047w8V8W8(377^7`6i6k7~7?3W5c8 6O8y8h8!7S989a8+8I5E9k5S6e5U5z7-817:0W0/8`8S8d9b8W8Y040P0v0e0J0C8`9d745-9y6;8F9I8:758K0 0F0D0e7{6L539P9R9T986+8e8X8,040R2D2I9Y6}9x8C9`9!7M8;9o70049*9,5X9.0W0j9|0D9~901:8T9^7z9`512Zae552m0T8.8{7u6*9(9O9Q9S9#8y5Pa29p9f9CaG5|5,0(9 1:92010y7sa78|045qaj6J9A7_6g9h7}6m9v5|5~am9VaZap53as57aDa+ayaY7NagaiaUaxaWaOaZ8ib18204aNaK78aQ7#98aXa~5uaI8j6ja(8ma*aV0u9D6P7:7D7F7Hb87@a!9g8k9j6a110q4+4$4NbE0q4Q1x0#4SbJ2!2W1~202Y5#1,2V4Q1Daw3W2O0N6Y0v0xae0C0i0 1p1r1t1v0$7Y321K3h1E0Z2+0$0H6_2H1g0$0vb|0J0$0e1h2a0E4V7F0:2l0$0?0E5z7F0h0$1t0T0$0T1l1!b.0$0R002l2u6_cd1-bD277F2b0#c0c2cx0:0!1eca0$0p0a0e0R0:0db{0T2H8#761N4Y2:3}1=1Z1#1%bX3}cv2w2y2A0f0J0E0}cD0w0Q251g4)4#8{314(bDc)4b7:4=7M6D5sa`0p4 04a:ar56aua@aV5ed88-dga 8U308w9_aHbwa$bya)85a.b5848%9J048tbodrb3bu3W8*8581aQaT4h8x5|8A69blbva4a`a68Ha88M6Z6#0l6%a`8Tb;dO9c9N947Q9sdH3}dJdAa3ada59%dj9{8^dl9l8}9ndYb95J7n9r7r9ta-9E0 br7Gb47Kazd/9698d+7U6P0F7#047%7)d)0 8udodP786dcvb4d@2Udx6d0B2k9?bn9LeF0 eBdWd|be9zcueIeu5ddieR9Zd`eVbddK9`dGeY6)040ueKexdqdQ0 0o1Wd(dTdI6D2_bke%dreOe*9W76f1aZ8M0H0T0*eJem3D9ceM7C6@2@e08rb0d}e)e~aLa1e_9zf0e45CeQftbf9{0WfsenaE8}ebbp67dSfnezedfg8beP04f3fweS0F6Xd#8Pfaa-eybvej8#9U8ofpfIbv95fhd{fOaz8@0p7ceJe3fB5|aQf!7SdNf^aV9ud,fdandF9Bbh9idvd^fC04f@8/dFe8fi4b7veCf(g9a8fm4pfdec049G0Fgge+fb10g2e:fJaA9;f$9$9Xd=6;f+fMf4b5fPf~bvaa9-6M0j9:aCeJfXgzbva|e}gl78eD3z9NgIguf2azgPacgRgZgVeLgp9`fAgdfof.d}eTe^fQgh6*eXh09egBgUe#b48hg5gjb6b4aQaS98e-gWg3a8g_d1a0g|gK8Ld9eUgK7gh3gNfxg;h8gGh5gneEf%hdhBaPe6bbeVhieLgqeebtfq6;8i7{bi8l3%bC4W2Vc|4P4ZbB0*0,0.0F04.
Question 2 : encode_texte_codage(texte, codage)

Il faut maintenant encoder le texte initial avec ce code obtenu.

Créer la fonction encode_texte_codage qui prend comme paramètre un texte et qui renvoie une chaîne de caractères contenant le codage binaire du texte.

###(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

.128013buS[,3_4l.(wnx/)paPk:hors1vc25mgyd]jieft =050I0M0O0s0L0j0z0P0C0j0s0z0z0Q010O0L0r010406050z0c0F0F0s0y0H040d0x0j0c0+0x0n050p0=0@0_0{0:0r04141b051e0p1e1g1b0:0I0L0B0Z0#0%0)0w0L0G0w0j1u0w0O0.050U0b0j0M1p0$0(011t1v1x1v0O1D1F1B0O0b0x0I0{1C0y1c0O0w0Z0~0z0r0s0n0)0D011H1r010N0W0M0n0s0F0M1B1)1+1:1J1?1F1_1{0.0a0P0t0y0x0r0x0z0L110n0P0S1%0y0y0M0C2g141~0n1c0p1#2t0O1Z1Y1!0I200)1x0n1^2d1B1m1o0!1I2D0L2F0n1V1n1B0r2m1c2r2t2X0;1*2h2L1;2Q0y0^0j0.0A2q2#0/2!1 2%1J2)2+0.0D2/1+2;2r2C012_0s2,040g2}2s0:302@0)33350i382 2#313e0.0E3h1d2V142J2w0I2A310C1V1|1c3s1f3q2Z152:053x0S2W3j3c010u0.0S0N3o3b1q1J0m0.0P3S3L3U3d0N0.1^3I0M0h0O0M0o3-0h3I0s0G0M3Z2?3#010-040l3_2$3{0n0.3-3/3^3F2~2=412M3|0.0f3h3Y3T4c43043=3@0z0h340r0w0s0b0T40313}0q0v3h060P4D4h3!4j443.3:3*4g4a310x0.0Q4M4i2(0b0.1x0z0O4w3M3}0l0q4B4E4F3`4c3O040N0x0y4S4G2(0.0C0_0s2o0M2m4?4,1;0x3W042O504b4^04453-4!3{3}4A48394*4*4N3M4k5b3+4L5h3K511J4P040k5d4H040s0r0r1^0I5y1;4$5G2^4_1V3?0M4o4q4s4u4Z5r5l5e0.0e5J3d4_4{4}4 5U4T1J3}0J4(5r4C4E5V4-0.2m0O0c0y135r4+581J0z1.0401015Z015v5x5)4@5K040K0x566a5t0)5I6h5 5!5a4J5p3y664y4B143*2t2U0M2t3B2u3u142x2w1U1W2w4t1F6A1n2;0p0S0U0W0z04.
Question 3 : encode_Huffman(texte)

Pour encoder un texte, en utilisant le codage de Huffman, il faut :

  • créer l'arbre de Huffman à partir du texte. La fonction arbre_Huffman(chaine) est intégré à l'IDE,
  • en déduire le dictionnaire de codage
  • encoder le texte.

Compléter la fonction encode_Huffman(texte), qui prend en paramètre une chaine de caractères, et renvoie une chaine de caractère, représentant un codage de Huffman du paramètre.

###(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

.128013buS,3_4l(wnx/)paPk:hors1vc25mgydieft =H050G0I0K0q0H0i0x0L0A0i0q0x0x0M010K0H0p010406050x0c0D0D0q0w0F040d0v0i0c0(0v0l050n0/0;0?0^0-0p041118051b0n1b1d180-0G0H0z0W0Y0!0$0u0H0E0u0i1r0u0K0+050R0b0i0I1m0Z0#011q1s1u1s0K1A1C1y0K0b0v0G0^1z0w190K0u0W0{0x0p0q0l0$0B011E1o010J0T0I0l0q0D0I1y1$1(1-1G1:1C1?1^0+0a0L0r0w0v0p0v0x0H0~0l0L0P1!0w0w0I0A2d111{0l190n1Y2q0K1W1V1X0G1}0$1u0l1=2a1y1j1l0X1F2A0H2C0l1S1k1y0p2j192o2q2U0.1%2e2I1.2N0w0=0i0+0y2n2Y0,2X1|2!1G2$2(0+0B2,1(2.2o2z012?0q2)040f2`2p0-2}2;0$30320h352|2Y2~3b0+0C3e1a2S112G2t0G2x2~0A1S1_193p1c3n2W122-053u0P2T3g39010s0+0P0J3l381n1G0k0+0L3P3I3R3a0J0+1=3F0I0g0N0c0J0J0=103C2{2/2Z3Y010*040j3W2:3@0l0+0A0u0S2C3|3?2J3^0+0o0t3e060L4e3V3Q473 040?0b2j3e4g3X470v0+0M4o3=3h0+4l2j3)3+3-1(452~3_3{3:2p4w3J4j41430I4F3J3_0o4c4f4p3}4i3M0H3u0g3$1S0q0E4Q4J044X461.4s044u4-4/4x041C1M4A0b2L0S4n4-4L3@4H4R3~4y0w4m4,2W4h1.4T4V4f544Z044O2L3(4(0P5c2-4_3J4=4@2U5t58045p3(0K0I0m5D0g3F4*5r3;5e1G56535M3a40425n57473_0e4v5Q2 4!4$5p5J5V5f495h4e5j1.3L042j0K0c0w3/5x5/2=5S4P4%0l3%5K36113%2q2R0I2q3y2r3r112u2t1R1T2t0q1B693o1k2.0n0P0R0T0x04.

Remarques

  1. Pour l'exercice le codage est « textualisé », alors que, dans la réalité, l'opération se passe au niveau des octets et est donc plus difficilement visible.
  2. En pratique, le dictionnaire de codage est transmis dans le fichier avec le texte à décoder.