---
title: "Tri par tas et arbres AVL"
date: "2023-03-24"
---

# Questions sur les notions du dernier cours (1/2)

* Comment représenter un tableau sous forme d'arbre binaire?

. . .

* Qu'est-ce qu'un tas?

. . .

```
        | 1 | 16 | 5 | 12 | 4 | 2 | 8 | 10 | 6 | 7 |
```

* Quel est l'arbre que cela représente?


# Questions sur les notions du dernier cours (2/2)


```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((1))-->id1((16));
    id0-->id2((5));
    id1-->id3((12));
    id1-->id4((4));
    id2-->id5((2));
    id2-->id6((8));
    id3-->id7((10));
    id3-->id8((6));
    id4-->id9((7));
    id4-->id10(( ));    
    style id10 fill:#fff,stroke:#fff
```

# Exercice

* Trier par tas le tableau

```
        | 1 | 2 | 4 | 5 | 6 | 8 | 10 | 12 | 16
```

* Mettez autant de détails que possible.
* Que constatez-vous?
* Postez le résultat sur matrix.

# L'algorithme du tri par tas (1/2)

\footnotesize

## Deux étapes

1. Entassement: transformer l'arbre en tas.
2. Échanger la racine avec le dernier élément et entasser la racine.

## Pseudo-code d'entassement de l'arbre (15 min, matrix)

. . .

```python
rien tri_par_tas(tab)
    entassement(tab)
    échanger(tab[0], tab[size(tab)-1])
    pour i de size(tab)-1 à 2 
        tamisage(tab, 0)
        échanger(tab[0], tab[i-1])

rien entassement(tab)
    pour i de size(tab)/2-1 à 0
        tamisage(tab, i)

rien tamisage(tab, i)
    ind_max = ind_max(tab, i, gauche(i), droite(i))
    si i != ind_max
        échanger(tab[i], tab[ind_max])
        tamisage(tab, ind_max)
```

# L'algorithme du tri par tas (2/2)

* Fonctions utilitaires

    ```python
    entier ind_max(tab, i, g, d)
        ind_max = i
        si tab[ind_max] < tab[g] && size(tab) > g
            ind_max = g
        si tab[ind_mx] < tab[d] && size(tab) > d
            ind_max = d
        retourne ind_max

    entier gauche(i)
        retourne 2 * i + 1
    
    entier droite(i)
        retourne 2 * i + 2
    ```


<!-- # L'algorithme du tri par tas (3/4)

\footnotesize

## Implémenter en C l'algorithme du tri par tas (matrix, 20min)

. . .

```C 
void heapsort(int size, int tab[size]) {
    heapify(size, tab);
    swap(tab, tab + size - 1);
    for (int s = size - 1; s > 1; s--) {
        sift_up(s, tab, 0);
        swap(tab, tab + s - 1);
    }
}
void heapify(int size, int tab[size]) {
    for (int i = size / 2 - 1; i >= 0; i--) {
        sift_up(size, tab, i);
    }
}
void sift_up(int size, int tab[size], int i) {
    int ind_max = ind_max3(size, tab, i, left(i), right(i));
    if (i != ind_max) {
        swap(tab + i, tab + ind_max);
        sift_up(size, tab, ind_max);
    }
}
```

# L'algorithme du tri par tas (4/4)

\footnotesize

## Fonctions utilitaires

. . .

```C
int ind_max3(int size, int tab[size], int i, int l, int r) {
    int ind_max = i;
    if (l < size && tab[ind_max] < tab[l]) {
        ind_max = l;
    }
    if (r < size && tab[ind_max] < tab[r]) {
        ind_max = r;
    }
    return ind_max;
}
void swap(int *a, int *b) {
    int tmp = *a;
    *a      = *b;
    *b      = tmp;
}
int left(int i) {
    return 2 * i + 1;
}
int right(int i) {
    return 2 * i + 2;
}
``` -->


# Complexités

::: columns

:::: column

## Complexité de la recherche

1. En moyenne?
2. Dans le pire des cas?

. . .

1. $O(\log_2(N))$
2. $O(N)$

::::

:::: column

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((10))-->id1((9));
    id0-->id8((  ));
    id1-->id2((7));
    id1-->id9((  ));
    id2-->id3((6));
    id2-->id10((  ));
    id3-->id4((5));
    id3-->id11((  ));
    style id8 fill:#fff,stroke:#fff
    style id9 fill:#fff,stroke:#fff
    style id10 fill:#fff,stroke:#fff
    style id11 fill:#fff,stroke:#fff
```

::::

:::

# Un meilleur arbre

* Quelle propriété doit satisfaire un arbre pour être $O(\log_2(N))$?

. . .

* Si on a environ le même nombre de nœuds dans les sous-arbres.

## Définition

Un arbre binaire est parfaitement équilibré si, pour chaque
nœud, la différence entre les nombres de nœuds des sous-
arbres gauche et droit vaut au plus 1.

* Si l'arbre est **parfaitement équilibré**, alors tout ira bien.
* Quelle est la hauteur (profondeur) d'un arbre parfaitement équilibré?

. . .

* $O(\log_2(N))$.


# Équilibre parfait ou pas?

::: columns

:::: column

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((W))-->id1((B));
    id0-->id8((Y));
    id1-->id2((A));
    id1-->id9((  ));
    id8-->id10((X));
    id8-->id11((  ));
    style id9 fill:#fff,stroke:#fff
    style id11 fill:#fff,stroke:#fff
```

::::

:::: column

. . .

```
É
Q
U
I
L
I
B
R
É
```

::::

:::

# Équilibre parfait ou pas?

::: columns

:::: column

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((16))-->id1((10));
    id0-->id2((19));
    id1-->id3((8));
    id1-->id4((12));
    id4-->id5((11));
    id4-->id6((  ));
    id2-->id7((17));
    id2-->id8((  ));
    id7-->id9((  ));
    id7-->id10((18));
    style id6 fill:#fff,stroke:#fff
    style id8 fill:#fff,stroke:#fff
    style id9 fill:#fff,stroke:#fff
```

::::

:::: column

. . .

```
P 
A
S 

É
Q
U
I
L
I
B
R
É
```

::::

:::

# Arbres AVL

\footnotesize

* Quand est-ce qu'on équilibre un arbre?

. . .

* A l'insertion/suppression.
* Maintenir un arbre en état d'équilibre parfait: cher (insertion, suppression).
* On peut "relaxer" la condition d'équilibre: profondeur (hauteur) au lieu du
  nombre de nœuds:
    * La hauteur $\sim\log_2(N)$.

## Définition

Un arbre AVL (Adelson-Velskii et Landis) est un arbre binaire de recherche dans
lequel, pour chaque nœud, la différence de hauteur entre le sous-arbre gauche et droit vaut au plus 1.

* Relation entre nœuds et hauteur:
$$
\log_2(1+N)\leq 1+H\leq 1.44\cdot\log_2(2+N),\quad N=10^5,\ 17\leq H \leq 25.
$$
* Permet l'équilibrage en temps constant: insertion/suppression $O(\log_2(N))$.

# Notation

* `hg`: hauteur du sous-arbre gauche.
* `hd`: hauteur du sous-arbre droit.
* `facteur d'équilibre = fe = hd - hg`
* Que vaut `fe` si l'arbre est AVL?

. . .

* `fe = {-1, 0, 1}`


# AVL ou pas?

::: columns

:::: column

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((12))-->id1((10));
    id0-->id2((19));
    id2-->id3((17));
    id2-->id4((97));
```

::::

:::: column

. . .

```
A
V
L
```

::::

:::

# AVL ou pas?

::: columns

:::: column

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((12))-->id1((1));
    id0-->id2((19));
    id2-->id3((17));
    id2-->id4((97));
    id4-->id5((37));
    id4-->id6((  ));
    style id6 fill:#fff,stroke:#fff
```

::::

:::: column

. . .

```
P
A
S

A
V
L
```

::::

:::

# Insertion dans un arbre AVL (1/N)

1. On part d'un arbre AVL.
2. On insère un nouvel élément.

::: columns

:::: column

* `hd ? hg`.
* Insertion de `4`?

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((12))-->id1((1));
    id0-->id2((19));
```

::::

:::: column

. . .

* `hd = hg`

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((12))-->id1((1));
    id0-->id2((19));
    id1-->id4((  ));
    id1-->id5((4));
    style id4 fill:#fff,stroke:#fff
```

* `fe = -1`

::::

:::

# Insertion dans un arbre AVL (2/N)

1. On part d'un arbre AVL.
2. On insère un nouvel élément.

::: columns

:::: column

* `hd ? hg`.
* Insertion de `4`?

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((12))-->id1((1));
    id0-->id2((19));
    id2-->id3((18));
    id2-->id4((  ));
    style id4 fill:#fff,stroke:#fff
```

::::

:::: column

. . .

* `hd < hg`

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((12))-->id1((1));
    id0-->id2((19));
    id2-->id3((18));
    id2-->id4((  ));
    id1-->id5((  ));
    id1-->id6((4));
    style id4 fill:#fff,stroke:#fff
    style id5 fill:#fff,stroke:#fff
```

* `fe = 0`

::::

:::

# Insertion dans un arbre AVL (3/N)

\footnotesize

1. On part d'un arbre AVL.
2. On insère un nouvel élément.

::: columns

:::: column

* `hd ? hg`.
* Insertion de `4`?

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((12))-->id1((1));
    id0-->id2((19));
    id1-->id3((  ));
    id1-->id4((6));
    id2-->id5((  ));
    id2-->id6((  ));
    style id3 fill:#fff,stroke:#fff
    style id5 fill:#fff,stroke:#fff
    style id6 fill:#fff,stroke:#fff
```

::::

:::: column

. . .

* `hd < hg`

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((12))-->id1((1));
    id0-->id2((19));
    id1-->id3((  ));
    id1-->id4((6));
    id4-->id5((4));
    id4-->id6((  ));
    id2-->id7((  ));
    id2-->id8((  ));
    style id3 fill:#fff,stroke:#fff
    style id6 fill:#fff,stroke:#fff
    style id7 fill:#fff,stroke:#fff
    style id8 fill:#fff,stroke:#fff
```

::::

:::

**Déséquilibre!** Que vaut `fe`?

. . .

* `fe = 2`

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

![Après insertion](figs/cas1a_gauche.png)

::::

:::: column

## Cas 1a

* Comment rééquilibrer?

. . .

* ramène `u`, `v` `w` à la même hauteur.
* `v` à droite de `A` (gauche de `B`)

![Après équilibrage](figs/cas1a_droite.png)

::::

:::

# Les cas de déséquilibre


::: columns

:::: column

## Cas 1b (symétrique 1a)

![Après insertion](figs/cas1b_gauche.png)

::::

:::: column

## Cas 1b (symétrique 1a)

* Comment rééquilibrer?

. . .

![Après équilibrage](figs/cas1b_droite.png)

::::

:::

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

![Après insertion](figs/cas2a_gauche.png)

::::

:::: 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`)

![Après équilibrage](figs/cas2a_droite.png)

::::

:::


# Les cas de déséquilibre


::: columns

:::: column

## Cas 2b (symétrique 2a)

![Après insertion](figs/cas2b_gauche.png)

::::

:::: column

## Cas 2b (symétrique 2a)

* Comment rééquilibrer?

. . .

![Après équilibrage](figs/cas2b_droite.png)

::::

:::
