Aller au menu - Aller au contenu

[Plan du site] Vous êtes ici --- > Le Site du Zéro > Les tutoriels > Non-Officiels > Programmation > Algorithmique > Le tri à paniers > Lecture du tutoriel

Le tri à paniers

Vous vous apprêtez à lire un tutoriel rédigé par un membre de ce site. Malgré tout le soin que ce membre a pu apporter au tutoriel, nous ne pouvons pas garantir que les informations contenues sur cette page sont exactes à 100%. Merci de garder cela en tête lorsque vous lirez cette page ;o)
Avatar
Auteur : GuilOooo
Note : 16 / 20 (6 votes)
Visualisations : 7 418

Plus d'informations Plus d'informations
Bonjour à tous :)
Aujourd'hui je vais vous montrer un nouvel algorithme de tri. Eh oui, encore un :) . Il va nous permettre de trier un tableau de nombres entiers (et pas réels, vous verrez pourquoi quand je vous donnerai le principe). Il est surtout utilisé lorsque vous voulez trier des entiers qui sont très proches les uns des autres, sans quoi l'algorithme commence à prendre beaucoup de place en mémoire. Mais c'est plutôt original comme méthode. Nous allons voir tout ça ensemble.

Mise à jour du 14/05/2007 : j'ai fait des modifications sur la complexité pour tenir compte de la boucle dans le calloc, que j'avais dans un premier temps oubliée.
Sommaire du tutoriel :
Icône du chapitre

Le principe

Le principe est assez simple. On va partir d'un exemple. Imaginons que j'aie cette liste à trier dans l'ordre croissant :

Code : Console
2 - 8 - 6 - 4 - 10 - 12 - 6 - 4


Bon. Dans le tri à paniers, la première étape, c'est de déterminer le nombre le plus petit de la liste, ainsi que le nombre le plus grand. Donc ici, ces nombres sont 2 et 12. Jusque là, c'est facile à comprendre et à implémenter :) .

Ensuite, nous allons créer 11 « paniers » : (12 - 2) + 1 = 11. Un panier est en réalité un compteur, que l'on initialise à 0. Il y en a (12 - 2) + 1 car c'est le nombre d'entiers compris entre 2 et 12. On crée donc un panier par nombre possible dans la liste (compris entre le minimum et le maximum). Chaque panier correspondra ainsi au nombre d'occurences dans la liste : le premier panier (numéro 2) contiendra le nombre de 2 dans la liste, le second (numéro 3) le nombre de 3 dans la liste, et ainsi de suite.

La formule pour avoir le nombre d'entiers entre min et max est (min-max)+1. Elle ne marche pas avec les réels, car entre deux réels il y a une infinité d'autres réels. Voilà pourquoi trier par paniers des réels est interdit : il y aurait une infinité de paniers !

Pour le moment on a donc :

Code : Console
Liste à trier : 

2 - 8 - 6 - 4 - 10 - 12 - 6 - 4


Paniers :

02 : 0

03 : 0

04 : 0

05 : 0

06 : 0

07 : 0

08 : 0

09 : 0

10 : 0

11 : 0

12 : 0


L'étape suivante, ça va être de parcourir la liste à trier, du début à la fin, et, pour chaque valeur rencontrée, de rajouter 1 « jeton » dans le panier qui lui correspond (c'est à dire incrémenter le compteur).

Code : Console
Liste à trier : 

2 - 8 - 6 - 4 - 10 - 12 - 6 - 4


Paniers :

02 : 1

03 : 0

04 : 2

05 : 0

06 : 2

07 : 0

08 : 1

09 : 0

10 : 1

11 : 0

12 : 1


Bon, c'est bien joli. En gros cet algo nous donne le nombre d'occurrences de chaque nombre de la liste. Qu'est-ce qu'on en fait ?


C'est tout bête. On va réécrire entièrement la liste à trier à l'aide des paniers. En gros, on prend le 1er panier, et on écrit sa valeur correspondante autant de fois qu'il y a de jetons dedans. On recommence avec le 2ème panier, le 3ème...

Exemple : dans le 1er panier, le 02, il y a 1 jeton : on écrit une fois 02 dans le tableau. Le panier suivant, 03, ne contient rien. On passe. Le 04 contient 2 jetons : on écrit deux fois le nombre 04 dans le tableau. Et ainsi de suite...

On obtient alors :

Code : Console
02 - 04 - 04 - 06 - 06 - 08 - 10 - 12


Hourra ! La liste est triée \o/ !

Implémentation (et exemples en C)

Mon implémentation en C de cet algorithme n'étant pas encore prête, je vais me contenter de vous donner les grandes idées.

La première chose à faire, c'est de créer deux entiers qui seront les minima et maxima du tableau à trier. Ensuite, avec une boucle, vous déterminez leur valeur (utilisez une seule boucle pour les deux, c'est plus rapide ;) ).

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
void tri_paniers(long liste[], size_t taille)
{
    /* Index utilise tout a la fin pour savoir ou on en est dans l'ecriture de la liste */
    size_t liste_curseur = 0;

    /* Tableau qui contient les paniers */
    long* paniers;

    /* Les bornes de la liste */
    long min = liste[0];
    long max = liste[0];

    /* Index pour les for */
    size_t i;

    for (i = 0; i < taille; i++)
    {
        if (liste[i] < min) 
            min = liste[i];
        if (liste[i] > max) 
            max = liste[i];
    }


Ensuite, créez un tableau de (max-min)+1 entiers de long. Ce tableau sera le groupe de paniers (chaque case étant un panier). Il faut l'initialiser a 0, donc on utilise calloc :

Code : C
1
paniers = calloc( (max-min+1), sizeof(long) );


Maintenant, il faut parcourir la liste pour incrémenter les paniers :

Code : C
1
2
3
4
for(i = 0; i < size; i++)
{
    paniers[liste[i]-min]++;
}


Ici, liste[i] est la valeur rencontrée, et on fait - min pour obtenir l'index, dans le tableau paniers, du panier correspondant à cette valeur.

Enfin, on parcourt les paniers tout en récrivant le tableau :

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
for(i = 0; i < (max-min)+1; i++)
    {
        size_t j;
        for(j = 0; j < paniers[i]; j++)
        {
            liste[liste_curseur] = min+i;
            liste_curseur++;
        }
    }
} /* Fin de la fonction */


Et maintenant liste est triée :) .

Ces codes sources sont là pour vous donner une idée, mais ne les recopiez pas tels quels. Ils ne sont pas adaptés pour être compilés directement, car ce n'est pas le but : je veux juste vous mettre sur la voie, pas vous mâcher le travail.

Petits calculs de complexité

Nous allons donc maintenant parler de la complexité de cet algorithme. Pour ceux qui ne connaissent pas, il s'agit de savoir combien d'opérations on doit faire pour trier un tableau de N chiffres, en utilisant notre méthode. La complexité peut nous servir à évaluer la vitesse d'un algorithme sur telle machine, ou encore à comparer les algorithmes entre eux.

Le problème, c'est qu'évaluer très précisément le nombre d'opérations est souvent long et/ou difficile (ça va ensemble :p ). On va donc se contenter de calculer un ordre de grandeur : la complexité. Pour faire cet ordre de grandeur, on va négliger les instructions, qui, sur les machines récentes, sont extrêmement rapides à exécuter (moins d'une milli-seconde). On va surtout s'intéresser aux boucles : ce sont elles qui prennent un temps non-négligeable. Et, pour faire simple, on va définir qu'un tour de boucle vaut 1. C'est la référence. Comme les boucles contiennent des instructions classiques qui sont super-rapides, il n'y a pas beaucoup de différences de l'une à l'autre (au niveau du temps), sauf s'il y a une boucle dans une boucle. Mais dans ce cas c'est une autre histoire :) .

Revenons donc au tri à paniers. Imaginons que nous lui donnions un tableau de 20 chiffres. Que va-t-il faire ?



Ainsi, on a 3*20 + (max-min)+1 tours de boucle. Bien. Ca nous fait 60+tailleIntervalle tours de boucle. Et comme on pourrait remplacer 20 par n'importe quel autre chiffre, on dit que pour un tableau de N chiffres, il faut donc 3*N + (max-min)+1 tours de boucle. C'est une première estimation.

Bon, cependant, il y a une chose que l'on a pas vue en complexité : les informaticiens et les logiciens estiment que, sur une machine moderne très rapide, le fait que l'algorithme mette une fois N, deux fois N où trois fois N (etc etc ...) tours pour s'exécuter n'est pas très important. Ce qui est important, c'est N. Quand N devient très très grand (plusieurs millions), le trois devient ridicule à côté et ne change plus grand chose.

Donc, quand on a 3*N tours de boucles, on "arrondit" tout ça à N, tout court. Ce qui nous done N + (max-min). On néglige aussi le +1, mais pas max-min car cette valeur peut devenir très très grande dans certains cas (si la liste est très disparate), contrairement à 3 qui restera toujours tout petit.

On note donc que cet algorithme a une complexité O(N + (max-min)). Ce qui fait que la complexité augmente avec le nombre d'éléments et la disparité de la liste. Par rapport aux autres algorithmes, c'est pas super, surtout quand la liste est très disparate. Mais face à une liste d'éléments très proches (les âges d'une classe [...]) ça peut servir, la différence devenant plus petite. Cet algorithme peut même se révéler bien plus rapide que les tris « classiques ».

Bon, eh bien voilà ! Vous savez maintenant trier des entiers avec cette nouvelle méthode, il ne vous reste plus qu'à l'implémenter :) .
Pour plus d'informations : l'article Wikipédia. Il faut enfin savoir que cet algorithme se nomme également tri par dénombrement, ou tri par comptage. Il en existe de légères variantes (comme partout), mais l'idée reste la même.

Merci d'avoir lu jusqu'au bout ! Si vous avez des questions, envoyez moi un MP. Vous pouvez laisser un petit commentaire si le tuto vous a plu (ou si vous voyez des choses à améliorer).

Ce tutoriel est mis à disposition sous contrat Creative Commons  - Paternité - Partage des conditions à l'identique. Ça signifie que vous pouvez le copier et le modifier librement, à condition de citer l'auteur original et de garder cette licence.
Retour en haut Retour en haut


Créé : le 10/04/2007 à 12:50:16
Modifié : le 22/08/2008 à 16:09:05
Avancement : 100%
Licence : Creative Commons BY-SA

Changer de design | En savoir plus | Plan du site | Politique d'accessibilité | Règles | RSS tutoriels | RSS news
Édité par Simple IT SARL : Nous contacter | Notre blog | Revue de presse | Publicité

Y'a plus rien à lire, faut remonter maintenant !

Hébergement web - Correction de tutoriels - Créer un site
Vous souhaitez apparaître ici ? Contactez-nous.

Nombre de connectés 435 Zéros connectés | Requêtes SQL 8 requêtes | Temps de génération de la page : Total (SQL) 2.1023s (2.0914s)