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
|
.128013oPf 8lkg5:+bry2a1}h3tvw=u6{e[(Sn]x_s-c)7im/4pd050U0C0v0q0P0g0K0e0M0g0q0K0K0y010v0P0T010406050K0z0Q0Q0q0n0o040F0b0g0z0/0b0G050R0_0{0}0 0@0T04051f181i0R1f0@0U0P0w0%0)0+0-0)0G0i0z0q0i0C0L0T0o0v0t160e0t0P0i0t0g1K0t0v0=050Y0m0g0C1r0*0,011J1L1N1L0v1T1V1R0v0n1g1F0%120K0T0q0G0-0p011X1t010d0!0C0G0q0Q0C1R1?1^1}1Z201V23250=0a0e0c0n0b0T0b0K0P150G0e0W1;0n0n0C0M2q18280G1g0R1F2D1-1/1.1S0U2a1u0P0G222n1R1o1q0(1Y2N2P0G0b2T1R0T2w1g2B2D2*0^1@2r2V1~2Z0n0|0g1R0q1I2w0d0-030J0J0M2!0C1N2Y0b0L0r380=0r180q2+2.0?2-292:1Z2=2@2_2{0C2}012 3133352Q380L1{040p3d3f1^3h2B2M013m0q2^1g2`0t2|2~30320W3w2Z3y0u0=0u3D2A3g0@3H3k0-3K3M053O3Q3s3S3v2O3x390S0=0S3#193%3i2/1s3l0b2?3L3o3P3q3R3u3U3@3W390j0=0j3}2*3(2.3I3,473:3t3T344d37390A0=0A4j3 3)423+443n3N3p3r4r3?363y0O0=0O4A3F4l3j4D3J4F464H484J3=4c4M390f0=0f4R2C1j2(182T2G0U1/2L3*014s2S1p1g2%0C2)3g3$3F054s52290P0U0-302B3y0r3o5a5c4b4t4(3a0e2e0C5j4s3V4v3a2D3e403I0h0=0W0d544.4C2W010x0=0e5E58415H0G0d0=0b0M0M0z2v220M0C0K5M5y4`0;040E5$5G2;0=0v0C0I5:5,4m5(0=0N0k5M0@3~553H5i015d2.3y3A3.0e624$5l3^3z1|5p5r4L6d670R3e0e6n5L5-3l0=0M0}5M6p5^4V0b0=0y6v5%4V5)0B0s5}5@595b630J5e393Y4H6a5k5t3X6f245q6M5s4u6V5w046o6w4U5H5A040d446C6q3+6s6;6x5H0b5J042O6^6+5.045:5=0C6J5O1~5)5|5 2C5~2,616L641^3y3`6R7g6T6#3_6W256h4%6d7k3D6)6)6D6,0=0P5D7b6(7z710M6 771Z6{7B177E6*7K6?046t0n763I796I7E5y6S6O0L4g7l7s6c4e7(7q6Y6b6U4f1R6l6(7x7`7G6r7T6u7!6=015)0D7W4`0G6@806_780=0H7J3I6z040l6B7P7|0-0Q0P3b7Z7e4m7$654w5h7m6!5m4x5o6X7+7=0L4x6%7`6n8l016-340K7589701Z7Y7E7d537f5j7%4O7*6Z6i7-4O8B7r8$7t8(7@6m8I7y81877~7V8Q7R820=848`4n888r8R0-5)8d8k818g8j2*7Q3I8n8p8U7W8t7i4)8w8D7o0L4*8*7:7n5m4*8H6o8K6-2w0v5W7O9b8K8@7U8q530R574/514;4~180v4@9P2J2E0q1U9M0R4=5~0W0Y0!0K04.
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.
.128013oPf 8lkg5:j+,bry2a1Ch3tvw=u6e[(Sn9]_s-c)7im./4p0d050X0D0x0s0Q0g0L0e0N0g0s0L0L0A010x0Q0V010406050L0B0R0R0s0p0q040G0b0g0B0=0b0H050T0|0~10120`0V04051i1b1l0T1i0`0X0Q0y0*0,0.0:0,0H0i0B0s0i0D0M0V0q0x0v190e0v0Q0i0v0g1N0v0x0^050#0o0g0D1u0-0/011M1O1Q1O0x1W1Y1U0x0p1j1I0*150L0V0s0H0:0r011!1w010d0%0D0H0s0R0D1U1_1{201$231Y26280^0a0e0c0p0b0V0b0L0Q180H0e0Z1@0p0p0D0N2t1b2b0H1j0T1I2G1:1=1;1V0X2d1x0Q0H252q1U1r1t0+1#2Q2S0H0b2W1U0V2z1j2E2G2-0{1`2u2Y212$0p0 0g1U0s1L2z0d0:030K0K0N2%0D1Q2#0b0M0j0M0t0^0e0t1b0s2.2;0_2:2c2?1$2^2`2|2~0D3001323436382T3b0M1~040e0r3i3k1{3m2E2P013r0s2{1j2}0v2 3133350Z3B2$3D0w3f0w3J2D3l0`3N3p0:3Q3S053U3W3x3Y3A2R3C3c0U3f0U3+1c3-3n2=1v3q0b2_3R3t3V3v3X3z3!3}3$3c0j3f0j432-3.2;3O3=4d3_3y3Z374j3a3c0C3f0C4p453/483;4a3s3T3u3w4x3|393D0P3f0P4G3L4r3o4J3P4L4c4N4e4P3{4i4S3c0f3f0f4X2F4Z472Z4$4b3?3^4f3`4h4z4.0M0I3f0I4?3M4s3:4{4M3@4O4g4y3#4B3d0W0^0t0W584^4t4%4}5f505h4A3D0t3e045z5p465r4|4v4 4Q4-3~3d3F0t3I0T3j3,4Y5E5b4u4)4w4,525L0t3(5B3*5Q3K4@5U4#5W5e4*5g4R5#405B425*5S5,4I4`5/4~4+515i5y4m5B4o5{445T5~2@5s5H625w530t4D5B4F694q5-5 6e5X5I5Z643c0t4U5B4W6n4H5a5.6r5:5Y635x6w4:5B4=6B3L1m2+1b2W2J0X1=2O5b4y2V1s1j2*0D2,3l5|1j4y6)2c0Q0X0:332E5y3t6:6=6I6i1 2h0D6{6h5#1U5{6c1$0h0^3p6+6p210z3f7b763;0N0^0u367g6D4`0@040k6+0`6a2F5E6`016?2;3D3F5e7y6u6J3E6~27707z6|5L7D5*0e7R0e7c770^0Z0d7n4!4`7e3G7Z4_210d0R0^332R2s337(3O7q0F7=5b0o7q0L377Y7v6.7)1$7q0n6+7T7h3P0^0y3R0B0D7_4#84867U3;790v107}0x8f7p0^0O7s807u2/3N7F0K6@3c5%7E6;7M724k0M3(0e6 715?8I8D7Q7S8S8j017{0^7}0g7 8x7o210b0^0S8q2@8a8i888(040A8.8$3q8a8c8e8v7=8z8B0M5^8E8N5K8I408L7K935!95743j8S8T888W048Y8!6*8/8)8+8^040N0L8?7!8%0^8=80878@8k9q8m0p8o7t8}8F7A1{3D66928G8O5j4m9728996v3b9c3m807x9I8A7B4C6_9#8H5j4D9S7L7G536k3J9f9A010N5A030e0s0l0b171Z0B2u0o2s9}0e0i0s0B0N0v1Z2}0xa00x0e1Y0)4y9s8|9Z8y9#8 6y9N9:5L4U9.9U7Hat8R7R8U78047X9o0:7$7Tap9^0H0d0^0s0X0X0Ka58paM9u830^7^aX820:9h9jaI018h9y8U0H0^aVa+7q8u2-9zaY3;0o8X1:a?8sa^45a$0e8~9%0M6Lau7N8I4:ay9O945jb9aC9eaE0^0d4a9ta%899q10bp3O0b7$2Rbu7`7|7~a+8:8*b45V79an8#a{a,0^b25Tb4b69K3c554N8z9+3D55beav8IbU9?9eb)8Ua)bCbG4#bEa+a:9qbJ9l9^7q0Eb;79btb.8r040Jbzb/9wc35 a;2sc69v040mca1$b,8ZbD9nb 8,b?b004b{ck9p0Nb~bKbq7qc2aocub5arb75n9)az6i5lb!bb5jcD2G3j8wb^6/cBbS3d5AbabX6w3ecIcWcT9X9@bLaFaHcqaJ7fc+3PaP049 byc.7@a+cg9k6P88a-a_a/0^0b1I0D0pcn8t9GbQcR0H5y7D2}bW9Pdc7J9Tbf9acK7P9db)a`bqc`ci04bFczbH040yce0:8:0m9xc 88b=d2add5c.b:c.b=dzcycP2ubRdb6w8Dde9*dgdVdi9/cJ5y8Qdob*9gbBchdLcjdw5.aQaSaUc9c@a!a+0L3F015ld6d8czdT5y91dXcF5@d#e88I0t91bjc%bqdHd3dKd;4`dMelclaRaTa=d`04a#eo1$d}0^013ee1dQc|4se46w9Me7dk9V0t9R8MeK7HeM9XcOeEcQ6{8 6jcEeP6i9-eOb#cK9=ef7S8U9`0^9|0d0B2r192Saj0Dal360)2w9j0e0!0edId4e2dRcAeWcCateJe(5yaxe%d%6waBd*bk88aFbnek3ldq4t79cn85dN797ma.8/bx1afyaNd1ejdtdvf6dx9rfGb|042s0D0Rb@eUcva!d7eD7waqf8cS0tb9fbfg3dbdffc!f#c$dpeg3Odsd/dufMfKetcpew9B0NcncxdF9^8:dEfpd09qfx6o9Z0T6-6Q6(6S6#1b0x6Vgh2M2H0s1Xge0T6T7u0Z0#0%0L04.
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
.128013oP;f 8lkg5j:,bry2a1Ch}3tvw=u6{e[(Sn9]x_s-c)7iqm./4ép0d050$0F0y0s0T0h0O0f0Q0h0s0O0O0B010y0T0!010406050O0C0V0V0s0p0q040I0b0h0C0`0b0J050X111315170 0!04051n1g1q0X1n0 0$0T0z0/0;0?0^0;0J0j0C0s0j0F0P0!0q0y0v1e0f0v0T0j0v0h1S0v0y0}050*0o0h0F1z0=0@011R1T1V1T0y1#1%1Z0y0p1o1N0/1a0O0!0s0J0^0r011)1B010e0,0F0J0s0V0F1Z1~20251+281%2b2d0}0a0f0c0p0b0!0b0O0T1d0J0f0(1|0p0p0F0Q2y1g2g0J1o0X1N2L1^1`1_1!0$2i1C0T0J2a2v1Z1w1y0:1*2V2X0J0b2#1Z0!2E1o2J2L2=101 2z2%262+0p140h1Z0s1Q2E0e0^030N0N0Q2,0F1V2*0b0P0D0P0t0}0f0t1g0s2?2_0~2^2h2{1+2}2 31330F350137393b3d2Y3g0P23040f0r3n3p203r2J2U013w0s301o320v3436383a0(3G2+3I0x3k0x3O2I3q0 3S3u0^3V3X053Z3#3C3%3F2W3H3h0Y3k0Y3:1h3=3s2`1A3v0b2~3W3y3!3A3$3E3)423+3h0k3k0k482=3?2_3T3`4i3~3D3(3c4o3f3h0D3k0D4u4a3@4d3_4f3x3Y3z3B4C413e3I0S3k0S4L3Q4w3t4O3U4Q4h4S4j4U404n4X3h0g3k0g4$2K4(4c2(4+4g3{3}4k3 4m4E4?0P0K3k0K4{3R4x3^504R3|4T4l4D3*4G3i0#0}0t0#5d4}4y4,525k555m4F3I0t3j045E5u4b5w514A544V4=433i3K0t3N0X3o3;4%5J5g4z4.4B4;575Q0t3-5G3/5V3P4|5Z4*5#5j4/5l4W5*455G475/5X5;4N4 5@534:565n5D4r5G4t60495Y632|5x5M675B580t4I5G4K6e4v5=646j5$5N5(693h0t4Z5G4#6s4M5f5?6w5^5%685C6B4^5G4`6G6g6I6v5L6x6l5{4p3i5a5G5c6T626V6i6X6L6y6N580r5q046?5I6h4e6.665`5P6#0r5F726`6,6|5i6~5A6!5o0r3K7d754)6W785z5O5)715,0r5.5W6f6+7h6-7j5_7a707c5}0r5 7r6t6{4P6}7k6z6O3J6b0r6d7E6H7u774-6/6Z7z3I0r6p7Z7g4~7v7U797l6A3J6D0r6F7Q6U7S7H7w6M6m5Q0r6Q7|7$5K7^6:7`716%0r6)7;7t7%7T5y7x7+7L0x6@8g7 5!6K7*7K580x5F8p5d1r2:1g2#2O0$1`2T5g4D2!1x1o2/0F2;3q611o4D8I2h0T0$0^382J5D3y8P8R6;5*242m0F8X835o5F3:7G010Q5F031|0J0O1^0C2G0T1P2B0;0f1V8?1(0$000b0o0l0)0.4D0f2W2x0T0s0C0M8K0 7s8N2z8W018S2_7Y8V8Q9n8Y718!2c8$9t8(9q2L5W8,0i0}0(0e8K6u260A3k9J8,0J0e0}1I0y0N0e4f0)9O760^0|040H9Z7?3U0}0b0Q0Q0C2D2a0Q0F0O9)8a9#0}0R0m9h9_9a9s9o203,9r8%7ba50f8#a77X3h5,3O0fah0f9K3v0}9I9jaj8,0b0}0B8Kap9!019$0G0L9 9j5J9ma30J3I5}5jaE9u5o45aa9xac7maM1Z5/aiav9*9F049W0pauak3_0}0Qa05g9$0na+5?0}0za$aq9M042Wa?aw0J9,9.9:2E0J9?9^aCaq0}0Wa/640}2x0F0Vb42@8,9$0H9}aBbg4xaK8T4qa69za8bqaO2daQ7,6bagaVaia%9+aZb926ar04b8b5a|0}0s0!0!2a0$bG1+bibTa(040u3bbWax0}9(bL9*a}04a=b)9`b$040n0Eb#b+a*b.3T9$9~b`5g0O5F0000b#9$0w0R0Rbl8J3Sbo9p4Hbr8n5Q4Ibv9ycg6#6pbAahbDaY2E0y9:1faobDb+an6tb`cca43h6DaJa2aL4Y9wbwbsad0PcF5/9ibm8OcHbp0P6QcGbx7L4^cjcZ58cX608,8.0}8:cs0bcu1(1%0.0(9f0fbZ2B2B0z3W0F9:0.0V9b2 0Fc93QaDcUcd59cfcI3h5ac$cMaR3I6%8+awaY9Hb#a^ajb~5?9R04c^0M0Nd3cvcSb/bVdtbaaZ9X0yc49|b}cAdCa18XcV5sdd9A6B5qdhcl8)6@coaWb/b+dA3mcwb604atd+bMdHcsdK040Gb#d30}5tdF269$aA9jcRcabndacD3i8*32aKdUe7cKckdeec9C3LbC9P0}dA5U2=d$3TbId.eocxamdId?d^d}1+d`5Gd?e0dNe3cTdQdb5TdTbt5Redc%5*3Kd#bDc,048:1P0zd00y0fd)0W1y020h0y0d0Be#2W0re%0n2A1e0Q0fbQ2~1c0s2y0f0ZeY0Jct3c1%d72Kd9eIe65+eLcNfbdXeffbehaVcqbbcz3qep5!el2Wd*dO5gbIbKfta:b,a{9*bI020je+fAd%fq0JeneGb/fvb@a;d?dM4acBe5aG6BaIe9cHeb0taNabdi7,f#aT3obBejd:d)d?a.d/b*fIfK3Qfo4*erfG4yf^f;f~fp04f:e1a0cCfV3ibzfYeP6#0t4rfff!bzcQg7fU5Dcngcf(7L6oeOgq6ncnaUf.aXeva#f?fH04b_eta@bbdBfneud;9Yez9{d@d_0T0}f_f7bh0}0m0LfR5YfTf9g96Cfcdj6B4ZgheMg)fif-f{4 aY0Tfmf`gLgFfLeqb7fOfzgCg 04e)e+esgKekg4frb#fNgObEb-fx4 b|f69kdP9tdRcXgpdY5Dc#f%hs6Pf+eig=gygDg5hid~0}f=gGf/e/g2f|ashLdGg}d8gWb;hO2|fIfsh9aweUeW2z2E0V0!0;9?8~9@2Ad09gg6g$hoeJdlhrfgdghvh`hyhAfk044Eg`2Kg?hVgEhdh0hfb+hhhYfB0}h6e,hUalhbfJi8bJh1ichRawhkh;dOg87Yd!h_eb6?gthw3Jd!gxhAcphaemii0^f}h3g3hQi4eT8/0f1Ph%h)0sh+0Od01%2df2e.ilitg~iv3h72g*7,i.g.cNi.g;iHdn0}cscuiKb:b(hEijhDg~a,hGh1iJhf9$c8i*iqeHh?e67di/7Ljhi=g+3JeRgkh=aF7YafiyeM7piBefjwehe2jd9lgmi-fXhniC7CjxizaIjpiujE7Mji6=ggh|izgj9DhZiS0e0C2w8{h-150o2E0.0lj#0U0C0032h+j/c=32a!0)aa1(3af20T2a2Xe_1b0.j/000C2z0Z0h0Zi$dJjcgVe4g%7YgojHjycijUjvgwjXgzdw3Adq9Niadvj)2E0N0v0C0e0e14gJjCb{b%h1j`kej1gPbkkfhmi,7-jR7{g-koi?cPf,hB3TaY0A1Rf5iN5?0o0}2ld?j0j4fykMd?jbhIieh5fEihk,4 eBgUhmj504g!5;jq0NcV7|kV71huaPgu7{c)k#f-gLj3kIl5hHidhChKl0bHhNluijdxdza`j9kKiagAgNkOb:k`fSjOkii-h^klizh{lgjIdliFbBlmhchfhelHb+0l0blBlHdEl#g0lC04lJg#lLjfg98gld5ol^jl7,l^i^lWhak^lZi9l,04h%0beYk;j7ltl*9|hlf8l?3,e8lPeM8pjKml8*lVi0i|0pkHiQm1ewl.eylHeBd|md04eElK8J0X8M8t8H8v8E1g0y8ymO2R2M0s1$mL0X8w9i0(0*0,0O04.
# Tests(insensible Ă la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)