Langage C/C++

Le Tri par Insertion en C : Guide Complet

Dans cet article, nous allons explorer en détail comment implémenter le tri par insertion en C.

💡 Le tri par insertion est l’un des algorithmes de tri les plus simples et les plus intuitifs. Il consiste à parcourir un tableau d’éléments et à insérer chaque élément à sa place appropriée dans la partie triée du tableau. Bien que cet algorithme ne soit pas aussi efficace que certains autres, comme le tri rapide ou le tri fusion, il reste néanmoins intéressant à comprendre en raison de sa simplicité et de sa facilité de mise en œuvre.

Comprendre le Tri par Insertion

L’idée fondamentale du tri par insertion est de diviser le tableau en deux parties : une partie triée et une partie non triée. Au début, la partie triée est vide, tandis que la partie non triée contient tous les éléments du tableau. L’algorithme parcourt ensuite chaque élément de la partie non triée et l’insère à sa place correcte dans la partie triée. À chaque itération, la partie triée s’étend d’un élément supplémentaire, et la partie non triée diminue d’un élément. Ce processus se répète jusqu’à ce que tous les éléments soient triés.

Implémentation en C

Voici une implémentation simple du tri par insertion en langage C :

#include <stdio.h>

void insertionSort(int arr[], int n) {
    int i, key, j;
    for (i = 1; i < n; i++) {
        key = arr[i];
        j = i - 1;

        /* Déplace les éléments du tableau arr[0..i-1], qui sont
           plus grands que la clé, vers une position en avant
           de leur position actuelle */
        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];
            j = j - 1;
        }
        arr[j + 1] = key;
    }
}

int main() {
    int arr[] = {12, 11, 13, 5, 6};
    int n = sizeof(arr) / sizeof(arr[0]);
    insertionSort(arr, n);
    printf("Tableau trié : \n");
    for (int i = 0; i < n; i++)
        printf("%d ", arr[i]);
    printf("\n");
    return 0;
}

Dans cette implémentation, la fonction insertionSort trie le tableau passé en paramètre en utilisant le tri par insertion. La fonction main illustre son utilisation en triant un tableau d’entiers et en affichant le résultat trié.

Analyse de la Complexité

La complexité temporelle du tri par insertion dépend de la disposition initiale des éléments dans le tableau. Dans le pire des cas, lorsque le tableau est inversément trié, la complexité temporelle est quadratique, soit ( O(n^2) ). Cependant, dans le meilleur des cas, lorsque le tableau est déjà trié, la complexité temporelle est linéaire, soit ( O(n) ). En moyenne, le tri par insertion a une complexité temporelle de ( O(n^2) ).

La complexité spatiale du tri par insertion est linéaire, soit ( O(n) ), car elle nécessite un espace supplémentaire proportionnel à la taille du tableau pour stocker les éléments.

Voici quelques exemples pratiques illustrant l’utilisation du tri par insertion en C :

Exemple 1 : Tri de Nombres Entiers

Supposons que vous ayez un tableau d’entiers non trié et que vous vouliez le trier en utilisant le tri par insertion. Voici comment vous pourriez le faire en C :

#include <stdio.h>

void insertionSort(int arr[], int n) {
    int i, key, j;
    for (i = 1; i < n; i++) {
        key = arr[i];
        j = i - 1;

        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];
            j = j - 1;
        }
        arr[j + 1] = key;
    }
}

int main() {
    int arr[] = {12, 11, 13, 5, 6};
    int n = sizeof(arr) / sizeof(arr[0]);
    insertionSort(arr, n);
    printf("Tableau trié : \n");
    for (int i = 0; i < n; i++)
        printf("%d ", arr[i]);
    printf("\n");
    return 0;
}
Exemple 2 : Tri de Chaînes de Caractères

Supposons maintenant que vous ayez un tableau de chaînes de caractères et que vous souhaitiez les trier par ordre alphabétique en utilisant le tri par insertion :

#include <stdio.h>
#include <string.h>

void insertionSort(char *arr[], int n) {
    int i, j;
    char *key;
    for (i = 1; i < n; i++) {
        key = arr[i];
        j = i - 1;

        while (j >= 0 && strcmp(arr[j], key) > 0) {
            arr[j + 1] = arr[j];
            j = j - 1;
        }
        arr[j + 1] = key;
    }
}

int main() {
    char *arr[] = {"orange", "apple", "banana", "grape", "kiwi"};
    int n = sizeof(arr) / sizeof(arr[0]);
    insertionSort(arr, n);
    printf("Tableau trié : \n");
    for (int i = 0; i < n; i++)
        printf("%s ", arr[i]);
    printf("\n");
    return 0;
}

Ces exemples montrent comment vous pouvez utiliser le tri par insertion en C pour trier différents types de données, qu’il s’agisse de nombres entiers, de chaînes de caractères ou même d’autres types de données personnalisés.

Voici une version révisée avec des exemples de code pour chaque cas particulier :

Cas Particulier 1 : Tableau Déjà Trié

Si le tableau est déjà trié ou presque trié, le tri par insertion offre de bonnes performances. Voici un exemple de code :

#include <stdio.h>

void insertionSort(int arr[], int n) {
    int i, key, j;
    for (i = 1; i < n; i++) {
        key = arr[i];
        j = i - 1;

        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];
            j = j - 1;
        }
        arr[j + 1] = key;
    }
}

int main() {
    int arr[] = {2, 4, 6, 8, 10};
    int n = sizeof(arr) / sizeof(arr[0]);
    insertionSort(arr, n);
    printf("Tableau trié : \n");
    for (int i = 0; i < n; i++)
        printf("%d ", arr[i]);
    printf("\n");
    return 0;
}
Cas Particulier 2 : Taille du Tableau

Le tri par insertion peut être inefficace pour les grands tableaux. Voici un exemple illustrant son utilisation avec un grand tableau :

// Supposons un tableau de 10000 éléments
int arr[10000];

// Initialisez et remplissez le tableau ici...

// Tri par insertion
insertionSort(arr, 10000);
Cas Particulier 3 : Éléments Dupliqués

Le tri par insertion conserve l’ordre relatif des éléments dupliqués. Voici un exemple :

#include <stdio.h>

void insertionSort(int arr[], int n) {
    int i, key, j;
    for (i = 1; i < n; i++) {
        key = arr[i];
        j = i - 1;

        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];
            j = j - 1;
        }
        arr[j + 1] = key;
    }
}

int main() {
    int arr[] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3};
    int n = sizeof(arr) / sizeof(arr[0]);
    insertionSort(arr, n);
    printf("Tableau trié : \n");
    for (int i = 0; i < n; i++)
        printf("%d ", arr[i]);
    printf("\n");
    return 0;
}
Cas Particulier 4 : Espace Mémoire Supplémentaire

Le tri par insertion n’a pas besoin d’espace mémoire supplémentaire pour trier les éléments. Voici un exemple :

#include <stdio.h>

void insertionSort(int arr[], int n) {
    int i, key, j;
    for (i = 1; i < n; i++) {
        key = arr[i];
        j = i - 1;

        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];
            j = j - 1;
        }
        arr[j + 1] = key;
    }
}

int main() {
    // Utilisation d'un tableau existant
    int arr[] = {12, 11, 13, 5, 6};
    int n = sizeof(arr) / sizeof(arr[0]);
    insertionSort(arr, n);
    // Le tri est effectué dans le tableau existant, pas de mémoire supplémentaire nécessaire
    return 0;
}
Cas Particulier 5 : Performance en Moyenne

Le tri par insertion peut être plus efficace dans certains cas que d’autres algorithmes de tri. Voici un exemple où il est utilisé pour trier un petit tableau presque trié :

#include <stdio.h>

void insertionSort(int arr[], int n) {
    int i, key, j;
    for (i = 1; i < n; i++) {
        key = arr[i];
        j = i - 1;

        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];
            j = j - 1;
        }
        arr[j + 1] = key;
    }
}

int main() {
    // Tableau presque trié
    int arr[] = {2, 4, 3, 6, 5, 8, 7, 10, 9};
    int n = sizeof(arr) / sizeof(arr[0]);
    insertionSort(arr, n);
    printf("Tableau trié : \n");
    for (int i = 0; i < n; i++)
        printf("%d ", arr[i]);
    printf("\n");
    return 0;
}

Ces exemples illustrent différentes situations où le tri par insertion peut être utilisé en fonction des caractéristiques des données et des exigences de performance.

Voici comment nous pourrions illustrer le bon code versus le mauvais code pour chaque erreur technique à éviter lors de l’implémentation du tri par insertion en C :

Erreur 1 : Mauvaise Initialisation des Variables

Mauvais Code :

int i, j; // Non initialisées

Bon Code :

int i = 0, j = 0; // Initialisées à zéro
Erreur 2 : Utilisation d’indices incorrects

Mauvais Code :

while (arr[j] > key && j >= 0) { // Utilisation de j avant de vérifier s'il est supérieur ou égal à zéro

Bon Code :

while (j >= 0 && arr[j] > key) { // Vérification de j avant son utilisation
Erreur 3 : Mauvaise Manipulation des Limites du Tableau

Mauvais Code :

for (i = 0; i <= n; i++) { // Utilisation de <= n au lieu de < n

Bon Code :

for (i = 0; i < n; i++) { // Utilisation de < n pour rester dans les limites du tableau
Erreur 4 : Mauvaise Logique de Boucle

Mauvais Code :

for (i = n - 1; i >= 0; i++) { // Utilisation incorrecte de l'opérateur d'incrémentation

Bon Code :

for (i = n - 1; i >= 0; i--) { // Utilisation correcte de l'opérateur de décrémentation
Erreur 5 : Comparaisons Incorrectes

Mauvais Code :

while (arr[j] < key) { // Comparaison incorrecte (utilisation de < au lieu de >)

Bon Code :

while (arr[j] > key) { // Comparaison correcte (éléments triés en ordre croissant)
Erreur 6 : Oubli de l’Instruction de Tri

Mauvais Code :

while (j >= 0 && arr[j] > key) {
    // Instructions manquantes pour déplacer les éléments
}

Bon Code :

while (j >= 0 && arr[j] > key) {
    arr[j + 1] = arr[j];
    j--;
}
arr[j + 1] = key; // Instruction de tri
Erreur 7 : Oubli de la Condition de Boucle

Mauvais Code :

while (true) {
    // Boucle infinie sans condition de sortie
}

Bon Code :

while (j >= 0 && arr[j] > key) {
    // Condition de sortie définie à l'intérieur de la boucle
}

En respectant ces bonnes pratiques de codage, vous pouvez éviter les erreurs techniques courantes et assurer que votre implémentation du tri par insertion en C fonctionne correctement et produit les résultats attendus.

Autres articles

Guide : Implémenter get_iemedans des fichiers avec...
La fonction get_iemepermet de récupérer le i-ème élément d'un fichier...
Read more
Guide : Implémenter un Fichier en Tableau...
Les fichiers en tableaux circulaires (ou files d'attente circulaires )...
Read more
Guide : Fichiers en Tableaux Circulaires en...
Les tableaux circulaires (ou buffers circulaires) sont des structures de...
Read more

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *