Amphi 7 1
Plan
• Files de priorité
• Représentation par tas
• Tri par tas
• Codes préfixes
• Codage de Huffman
• Codage de Huffman adaptatif
Amphi 7 2
Files de priorité
Une file de priorité est un type abstrait de donnéesopérant sur un ensemble ordonné, et muni des opérations suivantes :
• trouver le maximum,
• insérer un élément,
• retirer le maximum.
En inversant l'ordre, on obtient un type abstrait permettant de trouver le minimum et de le retirer.
Files de priorité
Exemples d'utilisation :
• Ordonnancement des tâches d'un système d'exploitation.
• Application boursière (d'après Rolf Ingold)
• Contrôle aérien
• etc.
Trouvé sur le Web ...
Perle donne l’avantage aux applications critiques en implantant la gestion des niveaux de priorité sur sa gamme de routeurs.
Afin d’améliorer les performances des réseaux en fonction des applications, Perle Systems a implanté dans ses routeurs un nouveau mode de gestion des files d’attente. Celui-ci permet à l’administrateur réseau de définir quatre niveaux de priorité (haute, normale, moyenne ou basse) pour une interface ou un protocole donnés. Tous les paquets qui entrent dans le routeur sont affectés à une file d’attente en fonction d’un degré d’urgence défini au préalable. Les paquets affectés à la file ayant une priorité haute sont transmis les premiers. Lorsque cette file est vide, c’est le tour des paquets affectés à la file ayant la priorité immédiatement inférieure. Ce système permet de ne pas retarder la transmission des données prioritaires lorsque le réseau est encombré.
Amphi 7 5
Trouvé aussi sur le Web: application boursière
• Une commande comprend trois champs (action, prix, quantité), où action est un achat ou une vente, prix est le prix proposé et quantité est le nombre d’actions.
• Une cote donne l’offre la plus haute et la demande la plus basse.
• Lorsqu'une transaction survient, on effectue une série de suppressions dans la liste des commandes.
• Les commandes peuvent être annulées à tout moment.
Amphi 7 6
Structure de données pour le marché boursier
Une structure pour les offres, une pour les demandes.Opérations supportées :
supprimer(demande) supprimer(offre)
Annuler
retirerMax() retirerMin()
Transaction
max() min()
Cote
insere(prix, quantité) insere(prix, quantité)
Commande
Demandes Offres
Actions
Source: Cours du Prof. Rolf Ingold de l'université de Fribourg
Implantation des files de priorité
Implantation Trouver Insérer Retirer
max max
Tableau non ordonné O(n) O(1) O(n) Liste non ordonnée O(n) O(1) O(1)*
Tableau ordonné O(1) O(n) O(1)
Liste ordonnée O(1) O(n) O(1)
Tas O(1) O(log n) O(log n)
* après avoir trouvé
Plan
• Files de priorité
• Représentation par tas
• Tri par tas
• Codes préfixes
• Codage de Huffman
• Codage de Huffman adaptatif
Amphi 7 9
Arbre binaire tassé
0 1
0
0
0
0
1
1 1
Un arbre binaire est dit tassé si son code est un segment initial pour l'ordre des mots croisés.
Code : {#, 0, 1, 00, 01, 10, 11, 000, 001, 010}
La hauteur d'un arbre tassé à n noeuds est !log2 n".
Amphi 7 10
Structure de tas (heap en anglais)
Un tas est un arbre binaire tassé tel que le contenu de chaque nœud soit supérieur ou égal à celui de ses fils.4 8
6 12
7 15
23
5 1
2
Représentation par tableau
4 8
6 12
7 15
23
5 1
2 0
1 2
3 4 5 6
7 8 9
Numéro d'un nœud (en largeur) = indice du tableau
23 15 7 12 5 6 1 4 8 2 11 3 0 1 2 3 4 5 6 7 8 9 10 11
Racine : nœud 0 Pour un nœud i, Parent : !(i-1)/2"
Fils gauche : 2i+1 Fils droit : 2i+2
Les tas en Java
23 15 7 12 5 6 1 4 8 2 11 3 0 1 2 3 4 5 6 7 8 9 10 11
class Tas {
int[] a;
int nTas;
Tas(int n) {...}
int maximum() {...}
void ajouter(int v) {...}
void supprimer(){...}
}
Amphi 7 13
Constructeur
Le constructeur crée un tableauclass Tas {
int[] a;
int nTas;
Tas(int n) {
nTas = 0;
a = new int[n];
} ...
}
Amphi 7 14
Maximum
Le maximum est le contenu de la racine.class Tas {...
int maximum() {
return a[0];
} }
Complexité : O(1).
23 15 7 12 5 6 1 4 8 2 11 3 0 1 2 3 4 5 6 7 8 9 10 11
Insertion
23 15 7 12 5 6 1 4 8 2 21 0 1 2 3 4 5 6 7 8 9 10 11
• Placer le nouveau nœud dans la première position libre (10)
• Permuter avec le parent jusqu'à l'obtention d'un tas
4 8
6 12
7 15
23
5 1
2 0
1 2
3 4 5 6
7 8 9
21
10 Complexité : 0(log n)
Après insertion de 21
4 8
6 12
7 21
23
15 1
2 0
1 2
3 4 5 6
7 8 9
2321 7 12 15 6 1 4 8 2 5 0 1 2 3 4 5 6 7 8 9 10 11 5
10
Amphi 7 17
Insertion en Java
void ajouter(int v) {
int i = nTas;
++nTas;
while (i > 0 && a[(i-1)/2] <= v) {
a[i] = a[(i-1)/2];
i = (i-1)/2;
}
a[i] = v;
}
Amphi 7 18
Retirer le maximum
2 4
9 8
11 15
16
14 3
7 0
1 2
3 4 5 6
7 8 9
• Donner à la racine la valeur du dernier nœud.
• Supprimer le dernier nœud.
• Echanger avec le plus grand fils jusqu'à l'obtention d'un tas.
16 15 11 8 14 9 3 2 4 7 10 3 0 1 2 3 4 5 6 7 8 9 10 11 10
10 Complexité : O(log n)
Retirer le maximum
2 4
9 8
11 15
10
14 3
7 0
1 2
3 4 5 6
7 8 9
En Java
void supprimer() {
int v = a[0] = a[--nTas];
int i = 0;
while (2*i + 1 < nTas) { int j = 2*i + 1;
if (j + 1 < nTas && a[j+1] > a[j]) ++j;
if (v >= a[j]) break;
a[i] = a[j];
i = j;
}
a[i] = v;
}
Amphi 7 21
Plan
• Files de priorité
• Représentation par tas
• Tri par tas
• Codes préfixes
• Codage de Huffman
• Codage de Huffman adaptatif
Amphi 7 22
Tri par tas (heapsort)
On part d'un tableau vide a. On commence parconstruire un tas en ajoutant successivement au tas vide les éléments a[0], a[1], ...
On répète ensuite les opérations suivantes : - prendre le maximum,
- le retirer du tas,
- le mettre à droite du tas Complexité : O(n log n)
Trier (9, 2, 11, 7, 4, 14, 3, 16, 8, 10, 15)
9
2 9
9 2
11
2
9 7
11
4 2
7 9 11
9 4 2
11 7
14
...
On ajoute un à un les éléments:
Trier (5, 2, 11, 7, 4, 14, 3, 16, 8, 10, 15)
2 4
9 8
11 15
16
14 3
7 0
1 2
3 4 5 6
7 8 9
16 15 11 8 14 9 3 2 4 7 10 0 1 2 3 4 5 6 7 8 9 10 10
10
Une fois le tas obtenu...
Amphi 7 25
Trier (5, 2, 11, 7, 4, 14, 3, 16, 8, 10, 15)
2 4
9 8
11 14
15
10 3
7 0
1 2
3 4 5 6
7 8 9
15 14 11 8 10 9 3 2 4 7 16 0 1 2 3 4 5 6 7 8 9 10
On retire les éléments un à un.
Amphi 7 26
Trier (5, 2, 11, 7, 4, 14, 3, 16, 8, 10, 15)
2 4
9 8
11 10
14
7 3
0
1 2
3 4 5 6
7 8
14 10 11 8 7 9 3 2 4 15 16 0 1 2 3 4 5 6 7 8 9 10
On retire les éléments un à un.
Trier (5, 2, 11, 7, 4, 14, 3, 16, 8, 10, 15)
2
4 8
9 10
11
7 3
0
1 2
3 4 5 6
7
11 10 9 8 7 4 3 2 14 15 16 0 1 2 3 4 5 6 7 8 9 10
On retire les éléments un à un.
...
Tri par tas (heapsort) en Java
static int[] triParTas(int[] a) {
int n = a.length;
Tas t = new Tas(n);
for (int i = 0; i < n; i++) t.ajouter(a[i]);
for (int i = n-1; i >= 0; --i) {
int v = t.maximum();
t.supprimer();
a[i] = v;
}
return a;
}
Amphi 7 29
Plan
• Files de priorité
• Représentation par tas
• Tri par tas
• Codes préfixes
• Codage de Huffman
• Codage de Huffman adaptatif
Amphi 7 30
Codes préfixes
Un ensemble P de mots non vides est un code préfixe si aucun mot de P n'est préfixe propre d'un autre mot de P.Exemple : P = {0, 100, 101, 111, 1100, 1101}
Un mot admet au plus une décomposition comme produit de mots de P. La décomposition, si elle existe, s'obtient en lisant le mot de gauche à droite.
101010110111010110001010101001010100
Codes préfixes
Un ensemble fini de motsest un code préfixe si et seulement si c'est le code des feuilles d'un arbre binaire.
0 1
0
0
0
0 1
1 1
Code des feuilles : {00, 010, 101, 110}
Codes préfixes
Un code préfixe P est complet si tout mot estpréfixe d'un produit de mots de P.
Le code préfixe
{0, 100, 101, 111, 1100, 1101}
est complet :
1001010101011110110011011100101110 On peut compléter ce mot par 1.
Amphi 7 33
Codes préfixes complets
Un arbre binaire est ditcomplet si ses nœuds internes sont d'arité 2.
0 1
0
0
0 1
1 1
Code des feuilles : {00, 010, 011, 10, 11}
Un arbre binaire est complet ssi le code de ses feuilles est un code préfixe complet.
Amphi 7 34
Codage par code préfixe
Codage :a --> 00 d --> 10 b --> 010 r --> 11 c --> 011
b c
d
a r
0 1
0
0
0 1
1 1
abracadabra <-->
0001011000110010000101100 Décodage : unique par
lecture de gauche à droite.
Plan
• Files de priorité
• Représentation par tas
• Tri par tas
• Codes préfixes
• Codage de Huffman
• Codage de Huffman adaptatif
Compression de Huffman
Problème. Coder un texte à l'aide d'un code préfixe en minimisant la taille du texte codé.Exemples avec abracadabra
(1) a : 00, b : 010, c : 011, d : 10, r : 11.
0001011000110010000101100 --> 25 (2) a : 1, b : 000, c : 0010, d : 0011, r : 01 10000110010100111000011 --> 23
Remarque. La taille ne dépend que de la fréquence d'apparition de chaque lettre. 5 a, 2 b, 1 c, 1 d, 2 r
Amphi 7 37
Construction de l'arbre de Huffman (1)
Initialisation. Pour chaque lettre, un arbre réduit à sa racine. Sa valeur est la fréquence de la lettre.Itération. On fusionne les deux arbres de valeur minimale. La nouvelle racine a pour valeur la somme des valeurs des racines des deux arbres.
5 2 1 1 3
a b c d e
1 1
c d
2
Amphi 7 38
Construction de l'arbre de Huffman (2)
5 2 3
a b e
1 1
c d
2
(1)
5 3
a 2
b
e
1 1
c d
2 4
5 (2)
a 3 2
b
e
1 1
c d
2 4
7
(3)
c d
5
a 3 2
b
e
1 1
2 4
7 12
(4)
Codage a = 0 b = 100 c = 1010 d = 1011 e = 11
Utilisation de l'algorithme de Huffman.
• Le codage de Huffman donne un code préfixe optimal. (admis)
• Utilisé dans le fax et dans JPEG (compression d'images)
• On peut coder par groupes de 2 lettres ou plus (bitmaps).
• Il y a des techniques de compression sans perte de données nettement plus efficaces (codage
arithmétique, Ziv-Lempel, etc.)
Choix de la représentation de données.
• Si la taille de l'alphabet est N, l' arbre de Huffman est de taille 2N-1. On le représente ici par un tableau, où (le père de la racine est 0)
j si i est fils droit de j pere[i] =
-j si i est fils gauche de j
La création de l'arbre est contrôlée par un tas-min, dont les clés sont les fréquences des lettres.
• Note : on pourrait aussi utiliser deux files.
Amphi 7 41
Huffman en Java (1)
class Huffman { // Arbre à 2N - 1 nœuds final static int N = 26, M = 2*N - 1;
static int[] pere = new int[M];
static int[] freq = new int[M];
public static void main(String[] args) {
String s = args[0] ; calculFrequences(s);
creerArbre();
String[] tas = faireTable();
afficherCode(s, table);
} }
Amphi 7 42
Calcul des fréquences
static void calculFrequences(String s) {
for (int i = 0; i < s.length(); i++) freq[s.charAt(i) - 'a']++;
}
static int nombreLettres() {
int n = 0;
for (int i = 0; i < N; i++) if (freq[i] > 0)
n++;
return n;
}
Un tas-min avec clés
• Un tas-min est un tas pour l'ordre > . Autrement dit, le minimum est à la racine et le contenu de chaque nœud est inférieur au contenu de son fils gauche et de son fils droit.
• Un tas avec clés gère des données avec priorités : – les données sont dans le tableau (ici tas) – les priorités sont dans un deuxième tableau (ici
freq)
Un tas-min avec clés en Java
class Tas {
int[] tas; // contient les caractères int nTas = 0;
int[] freq; // fréquences des caractères Tas(int taille, int[] freq)
{
this.freq = freq;
nTas = 0;
tas = new int[taille];
} ...
}
Amphi 7 45
Ajouter à un tas-min (avec clé)
void ajouter(int v) {
int i = nTas;
++nTas;
while (i > 0 &&
freq[tas[(i-1)/2]] >= freq[v]) {
tas[i] = tas[(i-1)/2];
i = (i-1)/2;
}
tas[i] = v;
}
Amphi 7 46
void supprimer() {
int v = tas[0] = tas[--nTas];
int i = 0;
while (2*i + 1 < nTas) { int j = 2*i + 1;
if (j + 1 < nTas &&
freq[tas[j+1]] < freq[tas[j]]) ++j;
if (freq[v] <= freq[tas[j]]) break;
tas[i] = tas[j];
i = j;
}
tas[i] = v;
}
Supprimer dans un tas-min (avec clé)
int minimum() {
return tas[0];
}
Minimum
static void creeArbre() {
int n = nombreLettres();
Tas tas = new Tas(2*n - 1, freq);
for (int i = 0; i < N; ++i) if (freq[i] > 0)
tas.ajouter(i);
int n = tas.nTas;
// A suivre ...
}
Création de l'arbre
Amphi 7 49
static void creeArbre() { // ...
for (int i = N; i < N+n-1; ++i) {
int x = tas.minimum();
tas.supprimer();
int y = tas.minimum();
tas.supprimer();
freq[i] = freq[x] + freq[y];
pere[x] = -i;
pere[y] = i;
tas.ajouter(i);
} }
Création de l'arbre (2)
Amphi 7 50
static String code(int i) {
if (pere[i] == 0) return "";
return code(Math.abs(pere[i])) + ((pere[i] < 0) ? 0 : 1);
}
Codage
Transmission du code. Première solution
a : 0 b : 1010 c : 100 d : 1011 e : 11
a
e c
b d
On code le parcours préfixe : nœud interne 0, feuille 1
01[a]001[c]01[b]1[d]1[e]
où [x] est le code ASCII de x.
Transmission du code. Deuxième solution
7 6
2 1 2
3 5 11
a : 1 18
b : 0101 c : 011 d : 0100 e : 00
On calcule, puis on transmet des fréquences fictives donnant le même code de Huffman ! Ici 7, 1, 2, 2, 6, codées sur un petit nombre de bits.
43 41
14 12 13
a
c e
b d
25 39 80
123
a
c e
b d
Amphi 7 53
Plan
• Files de priorité
• Représentation par tas
• Tri par tas
• Codes préfixes
• Codage de Huffman
• Codage de Huffman adaptatif
Amphi 7 54
L'algorithme de Huffman adaptatif.
Inconvénients de l'algorithme de Huffman.
• Il faut lire le texte entièrement avant de lancer la compression.
• Il faut transmettre le code trouvé.
La version adaptative corrige ces défauts. Principe :
• On envoie le code d'un caractère c.
• La fréquence de c est incrémentée. On met à jour l'arbre de Huffman (voir plus loin).
• Le décodage mime le codage (même mise à jour).
Mise à jour de l'arbre.
On maintient une liste de parcours des nœuds - compatible avec l'ordre des clés
- dans lequel deux frères sont toujours consécutifs.
11
a 11 5 3 2 c e
b d
5 10
21 32
6 5
1 f
2
4 3 6 5
7 8
9 10
11
On démontre que, dans un arbre de Huffman, on peut toujours trouver un ordre de parcours possédant ces
propriétés.
Mise à jour après incrémentation.
Deux types d'opérations
• Partant de la feuille dont la clé est incrémentée, on remonte vers la racine en incrémentant les clés des nœuds rencontrés.
• Avant l'incrémentation, chaque nœud est permuté avec le dernier nœud de même clé dans l'ordre de parcours.
Amphi 7 57
Mise à jour après incrémentation.
11
a 11 5 3 3 c e
b d
5 10
21 32
6 5
1 f
2
3 4 6 5
7 8
9 10
11
11
a 11
6
c e 3 3
b d
5 10
21 32
5 6
f 2 1
3 4 6 5
7 8
9 10
11
Après incrément du nœud 1, avant incrément de son père.
Après incrément du nœud 5, avant incrément de son père.
Amphi 7 58
Mise à jour après incrémentation.
11 12
a
6
c e
3 3
b d
5 10
21 33
6
5
f
1
2 3 4
5
6 7
9
8 10 11
Après incrément des nœuds 1, 5, 9, 11.
Le nouvel ordre de parcours vérifie bien les deux propriétés.
Algorithme de Huffman. Statistiques
Contes de Grimm Données techniques BitsHuffman + Code Total
H. Adaptatif
Codage par digrammes Huffman
+ Code Total
H. Adaptatif
700 000 439 613 522 440 135 440 164 383 264 10 880 394 144 393 969
700 000 518 361 954 519 315 519 561 442 564 31 488 474 052 472 534