Skip to content

Commit

Permalink
maj Algo Tri
Browse files Browse the repository at this point in the history
  • Loading branch information
davy39 committed Apr 7, 2024
1 parent 4d0bfad commit 6bc81e4
Show file tree
Hide file tree
Showing 19 changed files with 169 additions and 141 deletions.
2 changes: 1 addition & 1 deletion docs/algo/proprietes.md
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@

</center>

??? example "Exemple"
??? example "Exemples"
Soit un algorithme qui demande en entrée le nombre $n$ de jours restant avant le bac, et qui prépare un élève au bac.

??? note "Complexité Constante"
Expand Down
2 changes: 1 addition & 1 deletion docs/algo/tris/.pages
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
nav:
- 1️⃣ Introduction au tri : index.md
- 1️⃣ Tri par insertion : insertion.md
- 1️⃣ Tri par sélection : selection.md
- 1️⃣ Tri par insertion : insertion.md
- 1️⃣ Exercices : exercices.md

24 changes: 11 additions & 13 deletions docs/algo/tris/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@



??? abstract "Le tri en informatique"
??? info "Intro : Le tri en informatique"
Dans la vie courante, les deux verbes trier et classer ne sont pas synonymes.
- **Trier** ou effectuer un tri c’est répartir les éléments en paquets correspondant à un certain critère : par exemple séparer les déchets selon leur nature, les personnes d’une assemblée selon leur sexe ou selon leur langue maternelle.

Expand All @@ -21,18 +21,21 @@
!!! info "Définition à retenir"
En informatique le **tri** est à prendre avec le sens de **classement**.

{{exercice(prem=1, titre="Algorithmes de tri")}}
Le lien suivant va nous aider à imaginer des algorithmes de tris en manipulant des cartes :

[Simulateur de jeu de cartes](https://deck.of.cards/){ .md-button target="_blank" rel="noopener" }
??? video "Vidéo : Les algorithmes de tri"
<iframe title="Les algorithmes de tri" width="560" height="315" src="https://peertube.lyceeconnecte.fr/videos/embed/cffa5c51-e0fa-4ef7-9437-743a683fc937" frameborder="0" allowfullscreen="" sandbox="allow-same-origin allow-scripts allow-popups"></iframe>

💡 Vous devez imaginer et expliquer une méthode qui permette de trier des cartes. Il y a beaucoup de méthodes possibles ! A vous d'en trouver au moins une !

??? example "Animation : Différentes méthodes de tri"

Changer le *type de tri* et cliquer sur *commencer* pour visualiser les étapes de l'algorithme.

:warning: Seuls les tris par **insertion** et **sélection** sont au programme en NSI.

<iframe loading="lazy" src="https://animations.interstices.info/methodes-tri/index.html" width="740" height="410" frameborder="0" scrolling="no" bis_size="{&quot;x&quot;:995,&quot;y&quot;:1284,&quot;w&quot;:740,&quot;h&quot;:410,&quot;abs_x&quot;:995,&quot;abs_y&quot;:1284}"></iframe>


??? python "Le tri natif en Python avec `sorted`"
??? python "Astuce Python : tri natif avec `sorted()` et `sort()`"
👉 En Python, vous pourrez utiliser la fonction `sorted`
=== "`help(sorted)`"
{{ IDE('scripts/help_sorted') }}
Expand All @@ -45,12 +48,7 @@




??? abstract "Compléments"
<iframe loading="lazy" src="https://animations.interstices.info/methodes-tri/index.html" width="740" height="410" frameborder="0" scrolling="no" bis_size="{&quot;x&quot;:995,&quot;y&quot;:1284,&quot;w&quot;:740,&quot;h&quot;:410,&quot;abs_x&quot;:995,&quot;abs_y&quot;:1284}"></iframe>

😊 Pour approfondir : [Interstices](https://interstices.info/les-algorithmes-de-tri/){ .md-button target="_blank" rel="noopener" }


??? abstract "Compléments"
Pour approfondir : [Interstices](https://interstices.info/les-algorithmes-de-tri/){ .md-button target="_blank" rel="noopener" }


116 changes: 54 additions & 62 deletions docs/algo/tris/insertion.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
# Tri par insertion

??? abstract "Insérer la clef"
!!! abstract "Principe du tri par insertion"
<center>
<iframe width="560" height="315" src="https://www.youtube.com/embed/bRPHvWgc6YM" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
</center>
<font color="blue">Pour un tableau `tab` de taille `n`</font>
<pre><code style="background-color:black;color:white;width:100%;font-size: large;"><b>
pour <font color="red">i</font> allant de 1 à n-1

**En résumé :**

L'opération, pour chaque position <b>`i`</b>, consiste à prendre l'éléments d'indice `i` (la clef) et à l'insérer à la bonne place dans le tableau des éléments d'indices `0` à`i - 1`. Ce processus assure que les `i` premiers éléments seront triés.

On pourra donc recommencer avec l'élément suivant (la clef suivante à l'indice `i + 1`).

**Algorithme :**

Pour un tableau `tab` de taille `n`

<pre><code>pour <font color="red">i</font> allant de 1 à n-1
<font color="green">clef</font> ← tab[<font color="red">i</font>]
insérer la clef au bon endroit dans tab
</b></code></pre>

??? info "Le tri par insertion en bref"

L'opération, pour chaque position <b>`i`</b>, consiste à prendre l'éléments d'indice `i` (la clef) et à l'insérer à la bonne place dans le tableau des éléments d'indices `0` à`i - 1`. Ce processus assure que les `i` premiers éléments seront triés.

On pourra donc recommencer avec l'élément suivant (la clef suivante à l'indice `i + 1`).



Expand Down Expand Up @@ -64,11 +70,6 @@

---

Il est important de s'attarder sur deux points :

* à quels éléments est-il **indispensable** d'appliquer l'algorithme ?
* sous quelle condition peut-on décaler des éléments ?

???+ question "À quels éléments est-il **indispensable** d'appliquer l'algorithme ?"

=== "Cocher la ou les affirmations correctes"
Expand Down Expand Up @@ -146,14 +147,17 @@
);
</script>
</section>

=== "En python"

Avant de transcrire en Python l'algorithme, gardons à l'esprit que :

* il n'est pas indispensable d'aborder **tous** les éléments du tableau,
* l'élément abordé dans une itération doit être stocké dans **une variable temporaire**,
* la condition pour savoir s'il est possible de décaler des éléments est **double**,
* lors de chaque décalage, on **duplique** un élément.

=== "En python"
Compléter la fonction `#!py tri_insertion` prenant en argument un `#!py tableau` et le triant **en place** à l'aide du tri par insertion.

{{ IDE('scripts/insertion') }}
Expand Down Expand Up @@ -259,36 +263,30 @@
- :x: Lors de la dernière itération, la dernière valeur remonte en première position. Il faut effectuer $19$ décalages


???+ question "Quel est le "pire des cas?""
???+ question "Complexité dans le "pire des cas?""

??? success "Solution"

Le **pire des cas** est atteint lorsque le tableau est trié dans l'ordre décroissant. Dans ce cas, pour un tableau de $N$ valeurs :

**Dans le pire des cas** :
**Dans le pire des cas** :

* la boucle principale effectue $N-1$ itérations,
* la première boucle secondaire effectue $1$ décalage,
* la deuxième effectue $2$ décalages,
* la troisième $3$ décalages,
* ...
* la dernière boucle $N - 1$ décalages.
* la boucle principale effectue $N-1$ itérations,
* la première boucle secondaire effectue $1$ décalage,
* la deuxième effectue $2$ décalages,
* la troisième $3$ décalages,
* ...
* la dernière boucle $N - 1$ décalages.

On effectue donc au total $1 + 2 + 3 + \dots+(N-1)$ décalages. On retrouve la somme étudiée dans [cette page](../2_selection/#iii-complexite-du-tri-par-selection). Le coût de cet algorithme est donc **quadratique**.
On effectue donc au total $1 + 2 + 3 + \dots+(N-1)$ décalages. On retrouve la somme étudiée dans [cette page](../2_selection/#iii-complexite-du-tri-par-selection). Le coût de cet algorithme est donc **quadratique**.

!!! info "Dans le *meilleur* des cas ?"
???+ question "Complexité dans le "meilleur des cas?""
??? success "Solution"

Dans le cas où le tableau est initialement trié dans l'ordre croissant, l'algorithme n'effectuera qu'une seule comparaison et aucun échange à chaque itération de la boucle principale.
Le coût sera alors **linéaire**.
Dans le cas où le tableau est initialement trié dans l'ordre croissant, l'algorithme n'effectuera qu'une seule comparaison et aucun échange à chaque itération de la boucle principale.
Le coût sera alors **linéaire**.

!!! abstract "💚 A retenir"

La complexité du tri par insertion est quadratique : **Le coût est quadratique**.
On se place en effet dans le pire des cas : celui où le tableau est trié dans l'ordre décroissant.


{{exercice(titre="Mesures du temps de calcul")}}

??? note "On se place dans le pire des cas"
Expand Down Expand Up @@ -369,45 +367,42 @@
Cela correspond bien à une complexité **quadratique**

??? info "Visulalisation du temps de calcul"
{{jupyter('/algo/notebooks/temps_tri_insertion.ipynb')}}
{{jupyter('/notebooks/temps_tri_insertion.ipynb')}}


??? "Correction de l'algorithme de tri par insertion et invariant de boucle"

**Après la ième itération de la boucle for (boucle en i de l’algorithme fourni) les i premiers éléments sont triés.**
Cette propriété est un invariant de boucle pour le tri par insertion.
Cela se comprend aisément car dans chaque tour de boucle nous avions utilisé la fonction `insere` dont le rôle est de ranger les i premiers éléments de la liste par ordre croissant.

😀 Cet invariant de boucle prouve la correction du tri par insertion.
{{exercice(titre="Correction de l'algorithme de tri par insertion")}}

??? info "Terminaison de l'algorithme de tri par insertion"
Prouver la correction de l'algorithme à l'aide d'un invariant de boucle.

😒 La procédure de tri par insertion contient une boucle while.
??? success "Réponse"
*Après la ième itération de la boucle for (boucle en i de l’algorithme fourni) les i premiers éléments sont triés.*

A chaque fois qu'on écrit une boucle while, il faut s'interroger : est-on sûr que cette boucle va se terminer ?
Cette propriété est un invariant de boucle pour le tri par insertion.
Cela se comprend aisément car dans chaque tour de boucle nous avions utilisé la fonction `insere` dont le rôle est de ranger les i premiers éléments de la liste par ordre croissant.

Cet invariant de boucle prouve la correction du tri par insertion.

Rien de pire qu'un programme qui ne se termine jamais...
{{exercice(titre="Terminaison de l'algorithme de tri par insertion")}}
Justifier la terminaison à l'aide d'un variant de boucle.

Cette boucle s'arrête quand l'une des 2 conditions est fausse, donc quand :
??? success "Réponse"
La procédure de tri par insertion contient une boucle `while` :warning: : est-on sûr que cette boucle va se terminer ?

* `j <= 0`
* ou `tableau[j - 1] <= valeur_a_inserer`
Cette boucle s'arrête quand l'une des 2 conditions est fausse, donc quand :

??? info "Le variant de boucle"
* `j <= 0`
* ou `tableau[j - 1] <= valeur_a_inserer`

👀 regardons ce qu'il se passe en détail :
Avant la boucle, `j` vaut `i` et `0 <= i <n`.

😀 Notons que si `i = 0` on n'entre pas dans la boucle, elle se termine d'emblée sans commencer. La terminaison est alors évidente.
Notons que si `i = 0` on n'entre pas dans la boucle, elle se termine d'emblée sans commencer. La terminaison est alors évidente.

🏃 Sinon, on démarre avec `j` > 0, on entre donc dans la boucle.
Sinon, on démarre avec `j` > 0, on entre donc dans la boucle.

Dans le corps de la boucle, `j` est décrémenté de 1.

On a donc un entier positif qui décroît **strictement** à chaque itération.

Le mot strictement est ici crucial, car si ce n'était pas strictement, il se pourrait qu'on itère indéfiniment sans que `j` diminue, mais dans notre exemple, `j` diminue forcément.

Donc `j` finira par devenir négatif si on n'a pas été stoppé avant par l'autre condition.

Ceci prouve que la boucle se termine.
Expand All @@ -416,9 +411,11 @@

Ici, ce **variant de boucle** est une quantité qui décroît strictement et finit donc inévitablement par atteindre une valeur "plancher" qui assure la terminaison.

??? python "A mémoriser : l'algorithme du tri par insertion"

```python
??? mem "À retenir"

- Le tri par insertion a une complexité **quadratique**, c'est à dire de l'ordre du carré de la taille de la liste à trier $N^2$ : $O(n^2)$

```python title="Algorithme de tri par insertion"
def tri_insertion(tableau):
for i in range(1, len(tableau)):
valeur_a_inserer = tableau[i]
Expand All @@ -429,9 +426,4 @@
tableau[j] = valeur_a_inserer
```

??? info "A mémoriser : la complexité du tri par insertion"

Le tri par insertion a une complexité **quadratique**, c'est à dire de l'ordre du carré de la taille de la liste à trier.



1 change: 1 addition & 0 deletions docs/algo/tris/scripts/help_sorted test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

2 changes: 2 additions & 0 deletions docs/algo/tris/scripts/help_sorted_corr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
help(sorted)

2 changes: 1 addition & 1 deletion docs/algo/tris/scripts/mini_depuis.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ def indice_minimum_depuis(tableau, i):
i_mini = i
...


# Tests
assert indice_minimum_depuis([3, 8, 1, 5, 4], 0) == 2, "Erreur en partant de l'indice 0"
assert indice_minimum_depuis([3, 8, 1, 5, 4], 1) == 2, "Erreur en partant de l'indice 1"
assert indice_minimum_depuis([3, 8, 1, 5, 4], 2) == 2, "Erreur en partant de l'indice 2"
Expand Down
1 change: 1 addition & 0 deletions docs/algo/tris/scripts/mini_depuis_REM.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Dans le cas où le minimum apparaît plusieurs fois, on aurait pu aussi retenir la dernière d'entre elles. Le fonctionnement général de l'algorithme aurait été similaire (mais il n'aurait plus été [*stable*](https://fr.wikipedia.org/wiki/Algorithme_de_tri#Tri_stable))
6 changes: 6 additions & 0 deletions docs/algo/tris/scripts/mini_depuis_corr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
def indice_minimum_depuis(tableau, i):
i_mini = i
for j in range(i + 1, len(tableau)):
if tableau[j] < tableau[i_mini]:
i_mini = j
return i_mini
4 changes: 4 additions & 0 deletions docs/algo/tris/scripts/mini_depuis_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
assert indice_minimum_depuis([3, 8, 1, 5, 4], 0) == 2, "Erreur en partant de l'indice 0"
assert indice_minimum_depuis([3, 8, 1, 5, 4], 1) == 2, "Erreur en partant de l'indice 1"
assert indice_minimum_depuis([3, 8, 1, 5, 4], 2) == 2, "Erreur en partant de l'indice 2"
assert indice_minimum_depuis([3, 8, 1, 5, 4], 4) == 4, "Erreur en partant de l'indice 4"
2 changes: 1 addition & 1 deletion docs/algo/tris/scripts/selection.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def indice_minimum_depuis(tableau, i):
def tri_selection(tableau):
...


# Tests
tableau_0 = [3, 1, 2]
tri_selection(tableau_0)
assert tableau_0 == [1, 2, 3], "Erreur avec [3, 1, 2]"
Expand Down
3 changes: 0 additions & 3 deletions docs/algo/tris/scripts/selection_bis_corr.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,3 @@ def tri_selection(tableau):
i_mini = j
tableau[i], tableau[i_mini] = tableau[i_mini], tableau[i]




5 changes: 5 additions & 0 deletions docs/algo/tris/scripts/selection_corr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
def tri_selection(tableau):
for i in range(len(tableau) - 1):
i_mini = indice_minimum_depuis(tableau, i)
echange(tableau, i, i_mini)

15 changes: 15 additions & 0 deletions docs/algo/tris/scripts/selection_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
tableau_0 = [3, 1, 2]
tri_selection(tableau_0)
assert tableau_0 == [1, 2, 3], "Erreur avec [3, 1, 2]"

tableau_1 = [1, 2, 3, 4]
tri_selection(tableau_1)
assert tableau_1 == [1, 2, 3, 4], "Erreur avec [1, 2, 3, 4]"

tableau_2 = [-2, -5]
tri_selection(tableau_2)
assert tableau_2 == [-5, -2], "Erreur avec des valeurs négatives"

tableau_4 = []
tri_selection(tableau_4)
assert tableau_4 == [], "Erreur avec un tableau vide"
12 changes: 12 additions & 0 deletions docs/algo/tris/scripts/tri_sel_effet_corr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
def tri_selection(tableau):
for i in range(len(tableau) - 1):
i_mini = i
for j in range(i + 1, len(tableau)):
if tableau[j] < tableau[i_mini]:
i_mini = j
tableau[i], tableau[i_mini] = tableau[i_mini], tableau[i]

valeurs = [5, 1, 2]
print("valeurs = ", valeurs)
tri_selection(valeurs) # Appel de la fonction avec l'argument [5, 1, 2]
print("Après appel de la fonction de tri : valeurs = ", valeurs)
Empty file.
Loading

0 comments on commit 6bc81e4

Please sign in to comment.