Le code de Huffman et Shakespeare
1. Fonctionnement : le code de Huffman
Le code de Huffman est un algorithme de compression sans perte qui permet de représenter un texte de manière plus compacte en utilisant des codes binaires de longueur variable.
Principe :
- Les caractères fréquents reçoivent des codes courts
- Les caractères rares reçoivent des codes longs
- Les codes sont préfixes : aucun code n’est le début d’un autre.
Cela permet de décoder le message de manière non ambiguë.
L’algorithme fonctionne en trois étapes :
1. Calcul des fréquences de chaque caractère
2. Construction d’un arbre de Huffman
3. Déduction du code binaire de chaque caractère
Pour le texte de Shakespeare, nous allons construire le grand arbre suivant:

2. Récupération du texte de Macbeth
| Python |
|---|
| with open("macbeth.txt",'r') as f:
contenu = f.readlines()
texte = "".join(contenu) # join sert à concaténer les chaines d'une liste en ajoutant "" entre chaque élément
|
.128013it3advn{2S5wbcy+14: f-up8)_}eklohxrP=[s6(]/mg7050f0D0c0e0b0F0N0u0o0F0e0N0N0L010c0b0y010406050N0x0S0S0e0J0p040k0G0F0x0/0G0h050R0_0{0}0 0@0y04051f181i0R1f0@0f0b0g0%0)0+0-0)0h0T0x0e0T0D0w0y0p0c0H160u0H0b0T0H0F1K0H0c0=050Y0n0F0D1r0*0,011J1L1N1L0c1T1V1R0c0J1g1F0%120N0y0e0h0-0j011X1t010v0!0D0h0e0S0D1R1?1^1}1Z201V23250=0a0u0K0J0G0y0G0N0b150h0u0W1;0J0J0D0o2q18280h1g0R1F2D1-1/1.1S0f2a1u0b0h222n1R1o1q0(1Y2N2P0h0G2T1R0y2w1g2B2D2*0^1@2r2V1~2Z0J0|0F1R0e1I2w0v0-030B0B0o2!0D1N2Y0G0w0r380=0r180e2+2.0?2-292:1Z2=2@2_2{0D2}012 3133352Q380w1{040j3d3f1^3h2B2M013m0e2^1g2`0H2|2~30320W3w2Z3y0d0=0d3D2A3g0@3H3k0-3K3M053O3Q3s3S3v2O3x390s0=0s3#193%3i2/1s3l0G2?3L3o3P3q3R3u3U3@3W390l0=0l3}2*3(2.3I3,473:3t3T344d37390O0=0O4j3 3)423+443n3N3p3r4r3?363y0U0=0U4A3F4l3j4D3J4F464H484J3=4c4M390z0=0z4R2C1j2(182T2G0f1/2L3*014s2S1p1g2%0D2)3g3$3F054s52290b0f0-302B3y0r3o5a5c4b4t4(3a0u2e0D5j4s3V4v3a2D3e403I0E0=0W0v544.4C2W010m0=0u5E58415H0h0v0=0G0o0o0x2v220o0D0N5M5y4`0;040P5$5G2;0=0c0D0I5:5,4m5(0=0A0t5M0@3~553H5i015d2.3y3A3.0u624$5l3^3z1|5p5r4L6d670R3e0u6n5L5-3l0=0o0}5M6p5^4V0G0=0L6v5%4V5)0i0C5}5@595b630B5e393Y4H6a5k5t3X6f245q6M5s4u6V5w046o6w4U5H5A040v446C6q3+6s6;6x5H0G5J042O6^6+5.045:5=0D6J5O1~5)5|5 2C5~2,616L641^3y3`6R7g6T6#3_6W256h4%6d7k3D6)6)6D6,0=0b5D7b6(7z710o6 771Z6{7B177E6*7K6?046t0J763I796I7E5y6S6O0w4g7l7s6c4e7(7q6Y6b6U4f1R6l6(7x7`7G6r7T6u7!6=015)0M7W4`0h6@806_780=0Q7J3I6z040q6B7P7|0-0S0b3b7Z7e4m7$654w5h7m6!5m4x5o6X7+7=0w4x6%7`6n8l016-340N7589701Z7Y7E7d537f5j7%4O7*6Z6i7-4O8B7r8$7t8(7@6m8I7y81877~7V8Q7R820=848`4n888r8R0-5)8d8k818g8j2*7Q3I8n8p8U7W8t7i4)8w8D7o0w4*8*7:7n5m4*8H6o8K6-2w0c5W7O9b8K8@7U8q530R574/514;4~180c4@9P2J2E0e1U9M0R4=5~0W0Y0!0N04.
Pour Macbeth, on obtient :
| Python |
|---|
| occ = {
'A': 915, 'C': 571, 'T': 939, ' ': 25653, 'I': 666, '.': 1625,
'\n': 3863, 'S': 433, 'E': 603, 'N': 320, 'n': 4690, 'o': 5704,
'p': 960, 'e': 8609, 'l': 2981, 'a': 5118, 'c': 1580, '[': 174,
'h': 4801, 'u': 2390, 'd': 2942, 'r': 4224, 'i': 4007, 'g': 1222,
't': 6139, 'W': 449, 's': 4519, ']': 174, 'F': 299, 'R': 305,
'H': 460, 'w': 1488, 'm': 1840, ',': 1700, '?': 235, 'O': 348,
'D': 407, 'y': 1506, 'b': 1045, "'": 685, 'f': 1401, 'U': 195,
'M': 637, 'G': 106, 'k': 665, '!': 222, 'P': 51, 'L': 334,
':': 328, 'v': 635, 'K': 28, 'x': 94, ';': 374, 'q': 80,
'B': 410, 'j': 36, 'Y': 137, 'z': 16, 'X': 22, '-': 122,
'"': 52, 'Q': 36, 'V': 22, '&': 2, '(': 1, ')': 1, 'J': 2
}
|
3. Création d'un classe Code
La classe Code sert à représenter un sous-arbre dans la construction de l’arbre de Huffman. Chaque objet contient deux informations principales :
v : le poids du sous-arbre, c’est-à -dire la somme des occurrences des caractères qu’il contient.
cs : un dictionnaire des codes binaires associés aux caractères présents dans ce sous-arbre.
Ainsi, un objet Code représente à la fois un groupe de caractères et les codes binaires provisoires qui leur sont attribués pendant la construction de l’arbre de Huffman.
A l'initialisation les caractères seront placés dans des arbres racines sans code.
Exemple:
Cette classe comporte deux méthodes :
add_bit : ajoute un bit ("0" ou "1") au début de tous les codes des caractères contenus dans l’objet.
join : permet de fusionner deux sous-arbres, ce qui correspond à l’étape principale de l’algorithme de Huffman : on combine les deux nœuds de plus petit poids. L'attribut v devient égal à la somme des deux attributs v correspondants. L'attribut cs devient un dictionnaire contenant les codes des deux objets (après avoir été préfixés, l'un par "0", l'autre par "1"
Exemple:
| Python |
|---|
| c = Code(7, {"a": "10", "b": "11"})
c.add_bit("0")
c.cs
>>>{"a": "010", "b": "011"}
|
join sera appelé après avoir appelé add_bit sur self avec "0" comme argument et sur other avec "1" comme argument.
.128013Cit3a;dv,n2.S5wbcy+14q: f-up08)_j9eklohrP=[s6(]/mg7050h0J0d0f0c0L0S0y0r0L0f0S0S0Q010d0c0C010406050S0B0X0X0f0O0s040n0M0L0B0@0M0k050W0~1012140|0C04051k1d1n0W1k0|0h0c0i0,0.0:0=0.0k0Y0B0f0Y0J0A0C0s0d0N1b0y0N0c0Y0N0L1P0N0d0`050%0q0L0J1w0/0;011O1Q1S1Q0d1Y1!1W0d0O1l1K0,170S0C0f0k0=0l011$1y010z0)0J0k0f0X0J1W1{1}221(251!282a0`0a0y0P0O0M0C0M0S0c1a0k0y0#1_0O0O0J0r2v1d2d0k1l0W1K2I1=1@1?1X0h2f1z0c0k272s1W1t1v0-1%2S2U0k0M2Y1W0C2B1l2G2I2/0}1|2w2!232(0O110L1W0f1N2B0z0=030G0G0r2)0J1S2%0M0A0o0A0u0`0y0u1d0f2:2?0{2=2e2^1(2`2|2~300J32013436383a2V3d0A20040y0l3k3m1}3o2G2R013t0f2}1l2 0N313335370#3D2(3F0e3h0e3L2F3n0|3P3r0=3S3U053W3Y3z3!3C2T3E3e0v3h0v3-1e3/3p2@1x3s0M2{3T3v3X3x3Z3B3$3 3(3e0o3h0o452/3:2?3Q3@4f3{3A3#394l3c3e0T3h0T4r473;4a3?4c3u3V3w3y4z3~3b3F0Z3h0Z4I3N4t3q4L3R4N4e4P4g4R3}4k4U3e0E3h0E4Z2H4#492#4(4d3^3`4h3|4j4B4:0A0I3h0I4^3O4u3=4}4O3_4Q4i4A3%4D3f0D0`0u0D5a4`4v4)4 5h525j4C3F0u3g045B5r485t4~4x514S4/403f3H0u3K0W3l3.4!5G5d4w4+4y4.545N0u3*5D3,5S3M4_5W4%5Y5g4,5i4T5%425D445,5U5.4K4|5;504-535k5A4o5D4q5}465V602_5u5J645y550u4F5D4H6b4s5/616g5Z5K5#663e0u4W5D4Y6p4J5c5:6t5=5!655z6y4=5D4@6D3N1o2-1d2Y2L0h1@2Q5d4A2X1u1l2,0J2.3n5~1l4A6+2e0c0h0=352G5A3v6=6@6K6k212j0J6}6j5%1W5}6e1(0K0`3r6-6r230p3h7d783?0r0`0b387i6F4|0_040x6-0|6c2H5G6|016^2?3F3H5g7A6w6L3G7029727B6~5N7F5,0y7T0y7e790`0#0z7p4$4|7g3I7#4{230z0X0`352T2u357*3Q7s0U7@5d0q7s0S397!7x6:7+1(7s0j6-7V7j3R0`0i3T0B0J7{4%86887W3?7b0N127 0d8h7r0`0F7u827w2;3P7H0G6_3e5)7G6?7O744m0A3*0y71735^8K8F7S7U8U8l017}0`7 0L818z7q230M0`0m8s2_8c8k8a8*040Q8:8(3s8c8e8g8x7@8B8D0A5`8G8P5M8K428N7M955$97763l8U8V8a8Y048!8$6,8;8+8-8`040r0S8^7$8)0`8@82898_8m9s8o0O8q7v8 8H7C1}3F68948I8Q5l4o992a9b6x3d9e3o827z9K8C7D4E6{9%8J5l4F9U7N7I556m3L9h9C010r5C030y0f0H0M191#0B2w0q2u9 0y0Y0f0B0r0N1#2 0da20d0y1!0+4A9u8~9#8A9%916A9P9=5N4W9:9W7Jav8T7T8W7a047Z9q0=7(7Var9`0k0z0`0f0h0h0Ga78raO9w850`7`aZ840=9j9laK018j9A8W0k0`aXa-7s8w2/9Ba!3?0q8Z1=a^8ua`47a(0y909)0A6Naw7P8K4=aA9Q965lbbaE9gaG0`0z4c9va)8b9s12br3Q0M7(2Tbw7|7~80a-8=8,b65X7bap8%a}a.0`b45Vb6b89M3e574P8B9-3F57bgax8KbW9^9gb+8Wa+bEbI4%bGa-a=9sbL9n9`7s0Rb?7bbvb:8t040VbBb;9yc561a?2uc89x040tcc1(b.8#bF9pc18.b^b204b}cm9r0rc0bMbs7sc4aqcwb7atb95p9+aB6k5nb$bd5lcF2I3l8yb`6;cDbU3f5CbcbZ6y3gcKcYcV9Z9_bNaHaJcsaL7hc-3RaR04a1bAc:7_a-ci9m6R8aa/a{a;0`0M1K0J0Ocp8v9IbScT0k5A7F2 bY9Rde7L9Vbh9ccM7R9fb+a|bsc|ck04bHcBbJ040icg0=8=0t9zd18ab@d4afd7c:b=c:b@dBcAcR2wbTdd6y8Fdg9,didXdk9;cL5A8Sdqb,9ibDcjdNcldy5:aSaUaWcbc_a$a-0S3H020w0Bd40g0De1e30d0gd8dacBdV5A93dZcH5_d%ei8K0u93blc)bsdJd5dMd?4|dOevcnaTaVa@d|04a%ey1(d 0`e7e40ueKe9ebdSc~4uee6y9Oehdm9X0u9T8OeX7JeZ9ZcQeRcS6}916lcGe$6k9/e#b%cM9@ep7U8W9|0`9~0z0B2t1b2Ual0Jan380+2y9l0y0$0ydKd6ecdTcCe-cEaveWe^5Aaze@d)6yaDd,bm8aaHbpeu3nds4v7bcp87dP7b7oa:8;bz1cfLaPd3etdvdxfjdz9tfTb~042u0J0Xb_e+cxa$d9eQ7yasflcU0ubbfoft3fbffsc$f=c(dreq3Qdud;dwfZfXeDcreG9D0rcpczdH9`8=dGfCd29sfK6q9#0W6/6S6*6U6%1d0d6Xgu2O2J0f1Zgr0W6V7w0#0%0)0S04.
4. Création d'un forêt (ensemble d'arbres, ici une liste) et regroupement.
On va commencer par créer la liste de tous les arbres racines qui correspondent à chaque caractère, avec comme attribut v le nombre d'occurrences.
Puis, par itérations, on va chercher a chaque étape les deux arbres ayant les poids minimaux et les fusionner avec la méthode join après les avoir préfixé.
Pour cela on a besoin de 3 fonctions :
get_foret : construction de la liste d'objets code initiaux
deux_min: retourne les deux objets Code de valeurs minimales
arbre_huffman : fusion des arbres jusqu'a ce que la foret ne contienne plus qu'un élément
Code à compléter
.128013Cit3a;dv,n{2.S5éwbcy14q: f-up08j_)9}eklohxrP=[s6(]/mg7050h0L0d0f0c0N0V0z0t0N0f0V0V0T010d0c0D010406050V0C0!0!0f0R0u040o0O0N0C0`0O0k050Z111315170 0D04051n1g1q0Z1n0 0h0c0i0/0;0?0^0;0k0#0C0f0#0L0B0D0u0d0P1e0z0P0c0#0P0N1S0P0d0}050*0s0N0L1z0=0@011R1T1V1T0d1#1%1Z0d0R1o1N0/1a0V0D0f0k0^0m011)1B010A0,0L0k0f0!0L1Z1~20251+281%2b2d0}0a0z0S0R0O0D0O0V0c1d0k0z0(1|0R0R0L0t2y1g2g0k1o0Z1N2L1^1`1_1!0h2i1C0c0k2a2v1Z1w1y0:1*2V2X0k0O2#1Z0D2E1o2J2L2=101 2z2%262+0R140N1Z0f1Q2E0A0^030H0H0t2,0L1V2*0O0B0W0B0v0}0z0v1g0f2?2_0~2^2h2{1+2}2 31330L350137393b3d2Y3g0B23040z0m3n3p203r2J2U013w0f301o320P3436383a0(3G2+3I0e3k0e3O2I3q0 3S3u0^3V3X053Z3#3C3%3F2W3H3h0w3k0w3:1h3=3s2`1A3v0O2~3W3y3!3A3$3E3)423+3h0p3k0p482=3?2_3T3`4i3~3D3(3c4o3f3h0W3k0W4u4a3@4d3_4f3x3Y3z3B4C413e3I0$3k0$4L3Q4w3t4O3U4Q4h4S4j4U404n4X3h0F3k0F4$2K4(4c2(4+4g3{3}4k3 4m4E4?0B0J3k0J4{3R4x3^504R3|4T4l4D3*4G3i0E0}0v0E5d4}4y4,525k555m4F3I0v3j045E5u4b5w514A544V4=433i3K0v3N0Z3o3;4%5J5g4z4.4B4;575Q0v3-5G3/5V3P4|5Z4*5#5j4/5l4W5*455G475/5X5;4N4 5@534:565n5D4r5G4t60495Y632|5x5M675B580v4I5G4K6e4v5=646j5$5N5(693h0v4Z5G4#6s4M5f5?6w5^5%685C6B4^5G4`6G6g6I6v5L6x6l5{4p3i5a5G5c6T626V6i6X6L6y6N580m5q046?5I6h4e6.665`5P6#0m5F726`6,6|5i6~5A6!5o0m3K7d754)6W785z5O5)715,0m5.5W6f6+7h6-7j5_7a707c5}0m5 7r6t6{4P6}7k6z6O3J6b0m6d7E6H7u774-6/6Z7z3I0m6p7Z7g4~7v7U797l6A3J6D0m6F7Q6U7S7H7w6M6m5Q0m6Q7|7$5K7^6:7`716%0m6)7;7t7%7T5y7x7+7L0e6@8g7 5!6K7*7K580e5F8p5d1r2:1g2#2O0h1`2T5g4D2!1x1o2/0L2;3q611o4D8I2h0c0h0^382J5D3y8P8R6;5*242m0L8X835o5F3:7G010t5F031|0k0V1^0C2G0c1P2B0;0z1V8?1(0h02030e0J0g0O0s0G0)0.4D0z2W2x0c0f0C0Q8K0 7s8N2z8W018S2_7Y8V8Q9r8Y718!2c8$9x8(9u2L5W8,0M0}0(0A8K6u260r3k9N8,0k0A0}1I0d0H0A4f0)9S760^0|040X9%7?3U0}0O0t0t0C2D2a0t0L0V9-8a9)0}0I0y9l9}9e9w9s203,9v8%7ba90z8#ab7X3h5,3O0zal0z9O3v0}9M9nan8,0O0}0T8Kat9(019*0U0Ya39n5J9qa70k3I5}5jaI9y5o45ae9Bag7maQ1Z5/amaz9.9J049!0Rayao3_0}0ta45g9*0ja/5?0}0ia*au9Q042Wa`aA0k9:9=9@2E0k9`9|aGau0}0na?640}2x0L0!b82@8,9*0Xa1aFbk4xaO8T4qaa9DacbuaS2daU7,6bakaZama+9/a%bd26av04bcb9b00}0f0D0D2a0hbK1+bmbXa,040b3bb!aB0}9,bP9.b104a_b-9~b*040j0lb)b/a.b=3T9*a2b~5g0V5F93950gc696b)9*0K0I0Ibp8J3Sbs9t4Hbv8n5Q4Ibz9Ccn6#6pbEalbHa$2E0d9@1fasbHb/ar6tb~cja83h6DaNa6aP4Y9AbAbwah0BcM5/9mbq8OcObt0B6QcNbB7L4^cqc*58c(608,8.0}8:cz0OcB1(1%0.0(9j0zb%2B2B0i3W0L9@0.0!9f2 0Lcg3QaHc#ck59cmcP3h5ac-cTaV3I6%8+aAa$9Lb)a|anc25?9V04c 0Q0HdacCcZb?bZdAbea%9#0dcba0c1cHdJa58Xc$5sdk9E6B5qdocs8)6@cva!b?b/dH3mcDba04axd=bQdOczdR040Ub)da0}5tdM269*aE9ncYchbrdhcK3i8*32aOd#eecRcrdlej9G3LbG9T0}dH5U2=d-3TbMd^evcEaqdPd}d e41+e15Gd}e7dUeac!dXdi5Td!bx5Rekc.5*3Kd,bHc?048:1P0id70d0zd:0n1y020N0d0g0Te,2W0me.0j2A1e0t0zbU2~1c0f2y0z0qe)0kcA3c1%de2KdgePed5+eScUfid(emfieoaZcxbfcG3qew5!es2Wd;dV5gbMbOfAa@b:a 9.bM020#e=fHd.fx0keueNb?fCb{a^d}dT4acIecaK6BaMegcOei0vaRafdp7,f,aX3obFeqd`d:d}a=d_b.fPfR3Qfv4*eyfN4yf f{g5fw04f`e8a4cJf$3ibDf)eW6#0v4rfmf+bDcXgef#5Dcugjf/7L6oeVgx6ncuaYf^a#eCa)f}fO04b}eAa{bfdIfueBd{9$eG9 d~e00c0}g0febl0}0y0YfY5Yf!fggg6Cfjdq6B4ZgoeTg:fpf@g24 a$0cftg1gSgMfSexbbfVfGgJh604e:e=ezgRergbfyb)fUgVbIb;fE4 c0fd9odW9xdYc(gwd)5Dc,f.hz6Pf=epg|gFgKgchpe50}f|gNf_e_g9g3awhSdNh4dfg%b^hV2|fPfzhgaAe#e%2z2E0!0D0;9`8~9{2Ad79kgdg-hveQdshyfndnhCi1hFhHfr044Eh12Kg}h$gLhkh7hmb/hoh)fI0}hde?h#aphifQifbNh8ijhYaAhrh{dVgf7Yd+i0ei6?gAhD3Jd+gEhHcwhhetip0^g4hagahXibe!8/0z1Ph.h:0fh=0Vd71%2df9e^isiAh5iC3h72g;7,i^g^cUi^g{iOdu0}czcBiRb@b,hLiqhKh5a:hNh8iQhm9*cfi;ixeOh}ed7di_7Ljoi|g=3JeYgrh|aJ7YajiFeT7piIemjDeoe9jk9pgti@f(huiJ7CjEiGaMjwiBjL7Mjp6=gni3iGgq9Hh*iZ0A0C2w8{h@150s2E0.0Gj,0x0Cc90g32h=j_c|32a(0)ae1(3af90c2a2Xf01b0.j_j{0C2z0q0N0qi-dQjjg$ebg.7YgvjOjFcpj#jCgDj(gGdD3Adx9RihdCj:2E0H0P0C0A0A14gQjJb b+h8k2kmj8gWboknhti?7-jY7{g@kwi}cWf?hI3Ta$0r1RfciU5?0s0}2ld}j7jbfFkUd}jihPilhcfLiok@4 eIg#htjc04g+5;jx0Hc$7|k%71hBaTgB7{c:k-f@gSjakQldhOikhJhRl8bLhUlCiqdEdGa~jgkSihgHgUkWb@l2fZjVkqi@h ktiGi2lojPdsiMbFluhjhmhllPb/0G0OlJlPdLl-g7lK04lRg,lTjmgg8gll5om0js7,m0i l(hhl0l+igl@04h.0Oe)k|jelBl=a0hsffl~3,eflXeT8pjRmt8*l%i7j30RkPiXm9eDl_eFlPeIe3ml04eLlS8J0Z8M8t8H8v8E1g0d8ymW2R2M0f1$mT0Z8w9m0(0*0,0V04.
# Tests(insensible Ă la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)