Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
C
cours
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
jacquesw.ndoumben
cours
Commits
e9629bfa
Verified
Commit
e9629bfa
authored
1 year ago
by
orestis.malaspin
Browse files
Options
Downloads
Patches
Plain Diff
added cours 20
parent
67bd9a84
No related branches found
Branches containing commit
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
slides/cours_20.md
+891
-0
891 additions, 0 deletions
slides/cours_20.md
with
891 additions
and
0 deletions
slides/cours_20.md
0 → 100644
+
891
−
0
View file @
e9629bfa
---
title
:
"
Arbres
AVL
et
arbres
quaternaires"
date
:
"
2024-04-09"
---
# Rappel: Algorithme d'insertion
*
Insérer le noeud comme d'habitude.
*
Mettre à jour les facteurs d'équilibre jusqu'à la racine (ou au premier
noeud déséquilibré).
*
Rééquilibrer le noeud si nécessaire.
# Rappel: les cas de déséquilibre
::: columns
:::: column
## Cas 1a
*
`u`
,
`v`
,
`w`
même hauteur.
*
déséquilibre en
`B`
après insertion dans
`u`

::::
:::: column
## Cas 1a
*
Comment rééquilibrer?
. . .
*
ramène
`u`
,
`v`
`w`
à la même hauteur.
*
`v`
à droite de
`A`
(gauche de
`B`
)

::::
:::
# Rappel: Les cas de déséquilibre
::: columns
:::: column
## Cas 2a
*
`h(v1)=h(v2), h(u)=h(w)`
.
*
déséquilibre en
`C`
après insertion dans
`v2`

::::
:::: column
## Cas 2a
*
Comment rééquilibrer?
. . .
*
ramène
`u`
,
`v2`
,
`w`
à la même hauteur (
`v1`
pas tout à fait).
*
`v2`
à droite de
`B`
(gauche de
`C`
)
*
`B`
à droite de
`A`
(gauche de
`C`
)
*
`v1`
à droite de
`A`
(gauche de
`B`
)

::::
:::
# Rappel: Rééquilibrage
## Rotation simple

# Rappel: La rotation gauche-droite
## Le cas 2a/b

# Un petit exercice
*
Insérer les nœuds suivants dans un arbre AVL
```
25 | 60 | 35 | 10 | 5 | 20 | 65 | 45 | 70 | 40
| 50 | 55 | 30 | 15
```
```
```
# Suppression dans un arbre AVL
::: columns
:::: column
## Algorithme par problème: supprimer 10
```
{.mermaid format=pdf width=400 loc=figs/}
graph TD;
id0((8))-->id1((4));
id0-->id2((10));
id1-->id3((2));
id1-->id4((6));
id3-->id5((1));
id3-->id6(( ))
id4-->id7(( ))
id4-->id8((7))
id2-->id9((9))
id2-->id10((14))
id10-->id11((12))
id10-->id12((16))
style id6 fill:#fff,stroke:#fff
style id7 fill:#fff,stroke:#fff
```
::::
:::: column
. . .
## Algorithme par problème: supprimer 10
```
{.mermaid format=pdf width=400 loc=figs/}
graph TD;
id0((8))-->id1((4));
id0-->id2((12));
id1-->id3((2));
id1-->id4((6));
id3-->id5((1));
id3-->id6(( ))
id4-->id7(( ))
id4-->id8((7))
id2-->id9((9))
id2-->id10((14))
id10-->id11(( ))
id10-->id12((16))
style id6 fill:#fff,stroke:#fff
style id7 fill:#fff,stroke:#fff
style id11 fill:#fff,stroke:#fff
```
::::
:::
# Suppression dans un arbre AVL
::: columns
:::: column
## Algorithme par problème: supprimer 8
```
{.mermaid format=pdf width=400 loc=figs/}
graph TD;
id0((8))-->id1((4));
id0-->id2((12));
id1-->id3((2));
id1-->id4((6));
id3-->id5((1));
id3-->id6(( ))
id4-->id7(( ))
id4-->id8((7))
id2-->id9((9))
id2-->id10((14))
id10-->id11(( ))
id10-->id12((16))
style id6 fill:#fff,stroke:#fff
style id7 fill:#fff,stroke:#fff
style id11 fill:#fff,stroke:#fff
```
::::
:::: column
. . .
## Algorithme par problème: rotation de 12
```
{.mermaid format=pdf width=400 loc=figs/}
graph TD;
id0((9))-->id1((4));
id0-->id2((12));
id1-->id3((2));
id1-->id4((6));
id3-->id5((1));
id3-->id6(( ))
id4-->id7(( ))
id4-->id8((7))
id2-->id9(( ))
id2-->id10((14))
id10-->id11(( ))
id10-->id12((16))
style id6 fill:#fff,stroke:#fff
style id7 fill:#fff,stroke:#fff
style id9 fill:#fff,stroke:#fff
style id11 fill:#fff,stroke:#fff
```
::::
:::
# Suppression dans un arbre AVL
::: columns
:::: column
## Algorithme par problème: rotation de 12
```
{.mermaid format=pdf width=400 loc=figs/}
graph TD;
id0((9))-->id1((4));
id0-->id2((14));
id1-->id3((2));
id1-->id4((6));
id3-->id5((1));
id3-->id6(( ))
id4-->id7(( ))
id4-->id8((7))
id2-->id9((12))
id2-->id10((16))
style id6 fill:#fff,stroke:#fff
style id7 fill:#fff,stroke:#fff
```
::::
:::: column
. . .
1.
On supprime comme d'habitude.
2.
On rééquilibre si besoin à l'endroit de la suppression.
*
Facile non?
. . .
*
Plus dur....
::::
:::
# Suppression dans un arbre AVL 2.0
::: columns
:::: column
## Algorithme par problème: suppression de 30
```
{.mermaid format=pdf width=400 loc=figs/}
graph TD;
id0((50))-->id1((30));
id0-->id2((100));
id1-->id3((10));
id1-->id4((40));
id3-->id5(( ));
id3-->id6((20))
id2-->id7((80))
id2-->id8((200))
id7-->id9((70))
id7-->id10((90))
id9-->id11((60))
id9-->id12(( ))
id8-->id13(( ))
id8-->id14((300))
style id5 fill:#fff,stroke:#fff
style id12 fill:#fff,stroke:#fff
style id13 fill:#fff,stroke:#fff
```
::::
:::: column
. . .
## Algorithme par problème: rotation GD autour de 40
```
{.mermaid format=pdf width=400 loc=figs/}
graph TD;
id0((50))-->id1((40));
id0-->id2((100));
id1-->id3((10));
id1-->id4(( ));
id3-->id5(( ));
id3-->id6((20))
id2-->id7((80))
id2-->id8((200))
id7-->id9((70))
id7-->id10((90))
id9-->id11((60))
id9-->id12(( ))
id8-->id13(( ))
id8-->id14((300))
style id4 fill:#fff,stroke:#fff
style id5 fill:#fff,stroke:#fff
style id12 fill:#fff,stroke:#fff
style id13 fill:#fff,stroke:#fff
```
::::
:::
# Suppression dans un arbre AVL 2.0
::: columns
:::: column
## Argl! 50 est déséquilibré!
```
{.mermaid format=pdf width=400 loc=figs/}
graph TD;
id0((50))-->id1((20));
id0-->id2((100));
id1-->id3((10));
id1-->id4((40));
id2-->id7((80))
id2-->id8((200))
id7-->id9((70))
id7-->id10((90))
id9-->id11((60))
id9-->id12(( ))
id8-->id13(( ))
id8-->id14((300))
style id12 fill:#fff,stroke:#fff
style id13 fill:#fff,stroke:#fff
```
::::
:::: column
. . .
## Algorithme par problème: rotation DG autour de 50
```
{.mermaid format=pdf width=400 loc=figs/}
graph TD;
id0((80))-->id1((50));
id0-->id2((100));
id1-->id3((20));
id1-->id4((70));
id3-->id5((10));
id3-->id6((40));
id4-->id9((60))
id4-->id10(( ))
id2-->id7((90))
id2-->id8((200))
id8-->id13(( ))
id8-->id14((300))
style id10 fill:#fff,stroke:#fff
style id13 fill:#fff,stroke:#fff
```
::::
:::
# Résumé de la suppression
1.
On supprime comme pour un arbre binaire de recherche.
2.
Si un nœud est déséquilibré, on le rééquilibre.
*
Cette opération peut déséquilibrer un autre nœud.
3.
On continue à rééquilibrer tant qu'il y a des nœuds à équilibrer.
# Les arbres quaternaires
\H
uge Les arbres quaternaires
# Les arbres quaternaires
## Définition
Arbre dont chaque nœud a 4 enfants ou aucun.

# Les arbres quaternaires
## Cas d'utilisation
Typiquement utilisés pour représenter des données bidimensionnelles.
Son équivalent tri-dimensionnel est l'octree (chaque nœud a 8 enfants ou aucun).
## Cas d'utilisation: images
*
Stockage: compression.
*
Transformations: symétries, rotations, etc.
## Cas d'utilisation: simulation
*
Indexation spatiale.
*
Détection de collisions.
*
Simulation de galaxies, Barnes-Hut.
# Exemple de compression
::: columns
:::: {.column width=30%}
## Comment représenter l'image

::::
:::: {.column width=70%}
## Sous la forme d'un arbre quaternaire?
. . .

**Économie?**
. . .
Image 64 pixels, arbre 25 nœuds.
::::
:::
# Structure de données
::: columns
:::: {.column width=50%}
## Pseudo-code?
. . .
```
python
struct
node
info
node
sup_gauche
,
sup_droit
,
inf_gauche
,
inf_droit
```

::::
:::: {.column width=50%}
## En C?
. . .
```
C
struct _node {
int info;
struct _node *sup_left;
struct _node *sup_right;
struct _node *inf_left;
struct _node *inf_right;
};
```
*
Pourquoi le
`*`
est important?
. . .
*
Type récursif => taille inconnue à la compilation.
::::
:::
# Une fonctionnalité simple
\f
ootnotesize
## La fonction `est_feuille(noeud)`
*
Problème avec cette implémentation?
```
python
bool
est_feuille
(
noeud
)
retourne
est_vide
(
sup_gauche
(
noeud
))
&&
est_vide
(
sup_droit
(
noeud
))
&&
est_vide
(
inf_gauche
(
noeud
))
&&
est_vide
(
inf_droit
(
noeud
))
```
. . .
*
Inutile d'avoir 4 conditions (soit 4 enfants soit aucun!)
*
Facile d'en oublier un!
*
Comment changer la structure pour que ça soit moins terrible?
. . .
```
python
struct
node
info
node
enfant
[
4
]
```
# Structure de données
## En C?
. . .
```
C
typedef struct _node {
int info;
struct _node *child[4];
} node;
```
## Fonction `is_leaf(node *tree)`?
. . .
```
C
bool is_leaf(node *tree) {
return (NULL == tree->child[0]); // only first matters
}
```
# Problème à résoudre
*
Construire un arbre quaternaire à partir d'une image:
*
Créer l'arbre (allouer la mémoire pour tous les nœuds),
*
Le remplir avec les valeurs des pixels.
*
Compression de l'image:
*
Si les pixels sont les mêmes dans le quadrant on supprime le sous-arbre (sans perte)
*
Si les pixels dévient pas trop on supprime le quadrant (avec perte)
# Création de l'arbre
## Comment créer un arbre de profondeur `prof` (3min)?
. . .
```
python
arbre
creer_arbre
(
prof
)
n
=
nouveau_noeud
()
# alloue la mémoire
si
prof
>
0
pour
i
=
0
à
3
n
.
enfant
[
i
]
=
creer_arbre
(
prof
-
1
)
retourne
n
```
## En `C` (3 min, matrix)?
. . .
```
C
node *qt_create(int depth) {
node *n = calloc(1, sizeof(node));
if (depth > 0) {
for (int i = 0; i < 4; ++i) {
n->child[i] = qt_create(depth-1);
}
}
return n;
}
```
# Le nombre de nœuds?
## Comment implémenter la fonction (pseudo-code, 5min, matrix)?
. . .
```
C
entier nombre_nœuds(arbre)
si est_feuille(arbre)
retourne 1
sinon
somme = 1
pour i de 0 à 3
somme += nombre_nœuds(arbre.enfant[i])
retourne somme
```
# Le nombre de nœuds?
## Comment implémenter la fonction en C (3min, matrix)?
. . .
```
C
int size(node *qt) {
if (is_leaf(qt)) {
return 1;
} else {
int sum = 1;
for (int i = 0; i < 4; ++i) {
sum += size(qt->child[i]);
}
return sum;
}
}
```
# La profondeur en C?
## Implémentation (5min, matrix)
. . .
\f
ootnotesize
```
C
int max(int x, int y) {
return (x >= y ? x : y);
}
int max_depth(int depths[4]) {
int m = depths[0];
for (int i = 1; i < 4; ++i) {
m = max(m, depths[i]);
}
return m;
}
int depth(node *qt) {
int depths[] = {0, 0, 0, 0};
if (is_leaf(qt)) {
return 0;
} else {
for (int i = 0; i < 4; ++i) {
depths[i] = depth(qt->child[i]);
}
return 1 + max_depth(depths);
}
}
```
# Fonctions utiles (1/4)
## Comment remplir un arbre depuis une matrice?
```
SG=0 | SD=1
21 | 12 | 4 | 4
9 | 7 | 4 | 4
-----------------
1 | 1 | 0 | 31
1 | 1 | 3 | 27
IG=2 | ID=3
```
## Quel arbre cela représente?
. . .

# Fonctions utiles (2/4)
*
On veut transformer une ligne/colonne en feuille.
*
Comment?
::: columns
:::: {.column width=40%}
## Soit `ligne=2`, `colonne=3`
```
SG=0 | SD=1
21 | 12 | 4 | 4
9 | 7 | 4 | 4
-----------------
1 | 1 | 0 | 31
1 | 1 | 3 | 27
IG=2 | ID=3
```
::::
:::: {.column width=70%}
## Trouver un algorithme

*
Quelle feuille pour 31 (
`li=2`
,
`co=3`
)?
*
Plus important: quel chemin?
. . .
*
`co -> G/D`
,
`li -> S/I`
,
*
`2 * (li / 2) + co / 2 -> 2 * 1 + 1 = 3`
*
`2 * ((li % 2) / 1) + (co % 2) / 1 -> 2 * 0 + 1 = 1`
*
Comment généraliser?
::::
:::
# Fonctions utiles (3/4)
::: columns
:::: {.column width=40%}
## Soit `ligne=2`, `colonne=3`
```
SG=0 | SD=1
21 | 12 | 4 | 4
9 | 7 | 4 | 4
-----------------
1 | 1 | 0 | 31
1 | 1 | 3 | 27
IG=2 | ID=3
```
::::
:::: {.column width=70%}
## Trouver un algorithme (prendre plusieurs exemples, 15min, matrix)

*
Comment généraliser?
. . .
```
C
noeud position(li, co, arbre)
d = profondeur(arbre);
tant_que (d >= 1)
index = 2 * ((li % 2^d) / 2^(d-1)) +
(col % 2^d) / 2^(d-1)
arbre = arbre.enfant[index]
d -= 1
retourne arbre
```
::::
:::
# Fonctions utiles (4/4)
\f
ootnotesize
## Pseudo-code
```
C
noeud position(li, co, arbre)
d = profondeur(arbre);
tant_que (d >= 1)
index = 2 * ((li % 2^d) / 2^(d-1)) +
(col % 2^d) / 2^(d-1)
arbre = arbre.enfant[index]
d -= 1
retourne arbre
```
## Écrire le code `C` correspondant (5min, matrix)
```
C
```
# Remplir l'arbre
## A partir d'une matrice (pseudo-code, 5min, matrix)?
. . .
```
C
arbre matrice_à_arbre(matrice)
arbre = creer_arbre(profondeur)
pour li de 0 à nb_lignes(matrice)
pour co de 0 à nb_colonnes(matrice)
noeud = position(li, co, arbre)
noeud.info = matrice[co][li]
retourne arbre
```
. . .
## A partir d'une matrice (C, 5min, matrix)?
. . .
\f
ootnotesize
```
C
node *matrix_to_qt(int nb_li, int nb_co, int matrix[nb_li][nb_co], int depth)
{
node *qt = qt_create(depth);
for (int li = 0; li < nd_li; ++li) {
for (int co = 0; co < nd_co; ++co) {
node *current = position(li, co, qt);
current->info = matrix[li][co];
}
}
return qt;
}
```
# Remplir la matrice
## A partir de l'arbre (pseudo-code, 3min, matrix)?
. . .
```
C
matrice arbre_à_matrice(arbre)
matrice = creer_matrice(nb_lignes(arbre), nb_colonnes(arbre))
pour li de 0 à nb_lignes(matrice)
pour co de 0 à nb_colonnes(matrice)
noeud = position(li, co, arbre)
matrice[co][li] = noeud.info
retourne matrice
```
. . .
## A partir de l'arbre (C, 3min, matrix)?
. . .
\f
ootnotesize
```
C
void qt_to_matrix(node *qt, int nb_li, int nb_co, int matrix[nb_li][nb_co])
for (int li = 0; li < nd_li; ++li) {
for (int co = 0; co < nd_co; ++co) {
node *current = position(li, co, qt);
matrix[li][co] = current->info;
}
}
```
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment