Tris et recherche

1. Tri par Sélection

Fonctionnement :
Le tri par sélection fonctionne en divisant le tableau en deux parties : une partie triée et une partie non triée. À chaque itération, l'algorithme cherche l'élément le plus petit dans la partie non triée et l'échange avec le premier élément de cette partie. Ainsi, la partie triée grandit d'un élément à chaque itération.

Exemple :
Prenons le tableau
[64, 25, 12, 22, 11].

Le tableau est maintenant trié.

def tri_selection(tab):
    n = len(tab)
    for i in range(n - 1):
        min_index = i
        for j in range(i + 1, n):
            if tab[j] < tab[min_index]:
                min_index = j
        tab[i], tab[min_index] = tab[min_index], tab[i]

# Exemple
liste = [64, 25, 12, 22, 11]
tri_selection(liste)
print(liste)  # [11, 12, 22, 25, 64]

2. Tri par Insertion

Fonctionnement :
Le tri par insertion fonctionne en construisant progressivement une partie triée du tableau. À chaque itération, l'algorithme prend un élément de la partie non triée et l'insère à sa place dans la partie triée.

Exemple :
Prenons le tableau
[12, 11, 13, 5, 6].

Le tableau est maintenant trié.

def tri_insertion(tab):
    n = len(tab)
    for i in range(1, n):
        cle = tab[i]
        j = i - 1
        while j >= 0 and tab[j] > cle:
            tab[j + 1] = tab[j]  # Décaler à droite
            j -= 1
        tab[j + 1] = cle

# Exemple
liste = [12, 11, 13, 5, 6]
tri_insertion(liste)
print(liste)  # [5, 6, 11, 12, 13]

3. Tri par Fusion (Merge Sort)

Fonctionnement :
Le tri par fusion est un algorithme de tri récursif qui divise le tableau en deux moitiés, trie chaque moitié, puis fusionne les deux moitiés triées. La fusion consiste à combiner deux listes triées en une seule liste triée.

Exemple :
Prenons le tableau
[38, 27, 43, 3, 9, 82, 10].

Le tableau est maintenant trié.

def fusion(gauche, droite):
    resultat = []
    i = j = 0
    while i < len(gauche) and j < len(droite):
        if gauche[i] <= droite[j]:
            resultat.append(gauche[i])
            i += 1
        else:
            resultat.append(droite[j])
            j += 1
    # Ajouter le reste des éléments
    resultat.extend(gauche[i:])
    resultat.extend(droite[j:])
    return resultat

def tri_fusion(tab):
    if len(tab) <= 1:
        return tab
    milieu = len(tab) // 2
    gauche = tri_fusion(tab[:milieu])
    droite = tri_fusion(tab[milieu:])
    return fusion(gauche, droite)

# Exemple
liste = [38, 27, 43, 3, 9, 82, 10]
liste_triee = tri_fusion(liste)
print(liste_triee)  # [3, 9, 10, 27, 38, 43, 82]

4. Tri Rapide (Quick Sort)

Fonctionnement :
Le tri rapide est un algorithme de tri récursif qui choisit un élément pivot, puis partitionne le tableau en deux parties : une partie avec les éléments plus petits que le pivot et une partie avec les éléments plus grands que le pivot. Chaque partie est ensuite triée récursivement.

Exemple :
Prenons le tableau
[10, 7, 8, 9, 1, 5].

Le tableau est maintenant trié.

def tri_rapide(tab):
    if len(tab) <= 1:
        return tab
    pivot = tab[0]
    moins = [x for x in tab[1:] if x <= pivot]
    plus = [x for x in tab[1:] if x > pivot]
    return tri_rapide(moins) + [pivot] + tri_rapide(plus)

# Exemple
liste = [10, 7, 8, 9, 1, 5]
liste_triee = tri_rapide(liste)
print(liste_triee)  # [1, 5, 7, 8, 9, 10]

5. Tri à Bulle (Bubble Sort)

Fonctionnement :
Le tri à bulle fonctionne en comparant chaque paire d'éléments voisins et en les échangeant s'ils sont dans le mauvais ordre. Ce processus est répété jusqu'à ce que le tableau soit trié.

Exemple :
Prenons le tableau
[5, 1, 4, 2, 8].

Le tableau est maintenant trié.

def tri_bulle(tab):
    n = len(tab)
    for i in range(n):
        for j in range(0, n - i - 1):
            if tab[j] > tab[j + 1]:
                tab[j], tab[j + 1] = tab[j + 1], tab[j]

# Exemple
liste = [5, 1, 4, 2, 8]
tri_bulle(liste)
print(liste)  # [1, 2, 4, 5, 8]

6. Recherche Dichotomique (Binaire)

Fonctionnement :
La recherche dichotomique est un algorithme de recherche qui fonctionne sur des tableaux triés. Il compare la cible à l'élément du milieu du tableau. Si la cible est plus petite, la recherche continue dans la moitié gauche. Si la cible est plus grande, la recherche continue dans la moitié droite.

Exemple :
Prenons le tableau trié
[1, 3, 5, 7, 9, 11] et cherchons la cible 7.

La cible 7 est trouvée à l'indice 3.

def recherche_dichotomique(tab, cible):
    gauche = 0
    droite = len(tab) - 1
    while gauche <= droite:
        milieu = (gauche + droite) // 2
        if tab[milieu] == cible:
            return milieu  # Trouvé, retourne l’indice
        elif tab[milieu] < cible:
            gauche = milieu + 1
        else:
            droite = milieu - 1
    return -1  # Non trouvé

# Exemple
liste = [1, 3, 5, 7, 9, 11]
indice = recherche_dichotomique(liste, 7)
print(indice)  # 3

7. Algorithme de Dijkstra

Fonctionnement :
L'algorithme de Dijkstra est utilisé pour trouver le plus court chemin entre deux nœuds dans un graphe pondéré. Il fonctionne en maintenant une liste des distances les plus courtes connues depuis le nœud de départ jusqu'à chaque autre nœud. À chaque étape, l'algorithme sélectionne le nœud avec la distance la plus courte connue et met à jour les distances de ses voisins.

Exemple :
Prenons un graphe avec les nœuds
A, B, C, et D, et les arêtes suivantes : A-B (poids 1), A-C (poids 4), B-C (poids 2), B-D (poids 5), C-D (poids 1). Nous voulons trouver le plus court chemin de A à D.

Le plus court chemin de A à D est A -> B -> C -> D avec une distance totale de 4.

Voici le tableau des étapes de l'algorithme de Dijkstra pour ce graphe, montrant les distances minimales depuis A vers chaque nœud à chaque itération :

ÉtapeNœud traitéDistance ADistance BDistance CDistance DFile de priorité
Init0A
1A014B (1), C (4)
2B0136C (3), D (6)
3C0134D (4), D (6) (on garde 4)
4D0134

Chemin le plus court : A → B → C → D

Distance totale : 4

AlgorithmeMeilleur casPire casComplexité moyenneRemarque
SélectionO(n²)O(n²)O(n²)Simple mais lent
InsertionO(n)O(n²)O(n²)Bon pour presque trié
FusionO(n log n)O(n log n)O(n log n)Stable, bon pour gros tableaux
Rapide (QuickSort)O(n log n)O(n²)O(n log n)Rapide en pratique
BulleO(n)O(n²)O(n²)Pédagogique, peu utilisé
Recherche dichotomiqueO(1)O(log n)O(log n)Très efficace si trié