Leçon 13 sur 20

Chapitre 13 — Algorithmes de recherche

Localiser efficacement une valeur dans un ensemble de données

 

Fiche pédagogique du chapitre

Objectifs d’apprentissage

À la fin de ce chapitre, l’étudiant devra être capable de :

  • définir le problème de recherche d’une valeur dans un tableau ;
  • distinguer la présence, la position et le nombre d’occurrences d’une valeur ;
  • concevoir une recherche séquentielle avec ou sans arrêt anticipé ;
  • rechercher toutes les occurrences d’une valeur ;
  • construire et tracer une recherche dichotomique ;
  • expliquer pourquoi la recherche dichotomique exige un tableau trié ;
  • calculer correctement l’indice du milieu ;
  • mettre à jour les bornes gauche et droite sans perdre de valeur possible ;
  • écrire les versions itérative et récursive de la recherche dichotomique ;
  • comparer les méthodes selon le nombre d’opérations, la taille des données et leur organisation ;
  • identifier les cas favorables, moyens et défavorables ;
  • choisir la méthode de recherche adaptée à une situation donnée ;
  • élaborer des jeux d’essai et détecter les erreurs de bornes.

Prérequis

  • maîtriser les variables, conditions et boucles ;
  • savoir déclarer et parcourir un tableau à une dimension ;
  • connaître les fonctions, les paramètres et les valeurs de retour ;
  • comprendre la division entière ;
  • savoir construire une table de trace ;
  • connaître le principe d’un appel récursif.

Plan du chapitre

13.1 Recherche séquentielle

13.2 Recherche dichotomique

13.3 Comparaison des méthodes

Applications, tables de trace, travaux dirigés, corrigés et synthèse

Organisation pédagogique indicative

Activité

Durée indicative

Objectif principal

Cours3 hComprendre les deux méthodes et leurs conditions d’utilisation.
Travaux dirigés3 hTracer les recherches et corriger les erreurs de bornes.
Travaux pratiques3 hImplémenter, tester et comparer les algorithmes.
Travail personnel2 hConstruire des jeux d’essai et analyser le nombre de comparaisons.
Idée centrale : une recherche efficace ne dépend pas seulement de l’algorithme. Elle dépend aussi de l’organisation des données, notamment du fait que le tableau soit trié ou non.

Introduction aux algorithmes de recherche

Rechercher une information est une opération fondamentale en informatique. Un programme peut avoir besoin de vérifier l’existence d’un identifiant, de retrouver une note, de localiser un produit, de déterminer la position d’un nom ou de compter le nombre d’apparitions d’une valeur.

Le problème étudié dans ce chapitre consiste à rechercher une valeur appelée clé dans un tableau. Selon le besoin, l’algorithme peut retourner un booléen, l’indice de la première occurrence, la liste de toutes les positions ou le nombre d’occurrences.

Question posée

Résultat attendu

Exemple

La valeur existe-t-elle ?Vrai ou FauxLa note 15 est-elle présente ?
Où se trouve la valeur ?Un indice ou -1À quel indice se trouve « Sara » ?
Combien de fois apparaît-elle ?Un compteurCombien de notes égales à 10 ?
Où sont toutes ses occurrences ?Une collection d’indicesPositions de toutes les valeurs 0.

Deux stratégies seront étudiées. La recherche séquentielle examine les éléments dans leur ordre de stockage et fonctionne sur tout tableau. La recherche dichotomique élimine la moitié de la zone restante à chaque étape, mais elle n’est correcte que si les données sont triées selon un ordre compatible avec les comparaisons.

Convention utilisée : les indices commencent à 0. Un résultat égal à -1 signifie que la valeur recherchée n’a pas été trouvée.

13.1 Recherche séquentielle

13.1.1 Principe

La recherche séquentielle, également appelée recherche linéaire, consiste à comparer la clé recherchée avec les éléments du tableau, l’un après l’autre. Le parcours commence généralement au premier élément et avance jusqu’à la découverte de la valeur ou jusqu’à la fin du tableau.

Cette méthode ne suppose aucun ordre particulier. Elle peut donc être appliquée à un tableau trié, non trié, partiellement rempli ou contenant des doublons.

Étape

Action

1Initialiser l’indice au début du tableau.
2Comparer l’élément courant à la valeur recherchée.
3Si les valeurs sont égales, signaler la réussite.
4Sinon, passer à l’élément suivant.
5Si la fin est atteinte, signaler l’absence de la valeur.

13.1.2 Parcours complet du tableau

Un parcours complet examine tous les éléments. Il est nécessaire lorsque l’objectif est de compter les occurrences, de trouver toutes les positions ou de vérifier une propriété portant sur l’ensemble du tableau.

Recherche de l’existence par parcours complet

Fonction Existe(T : Tableau, n : Entier, x : Réel) : Booléen
Variables
    i : Entier
    trouve : Booléen
Début
    trouve ← Faux
    Pour i allant de 0 à n - 1 Faire
        Si T[i] = x Alors
            trouve ← Vrai
        FinSi
    FinPour
    Retourner trouve
Fin

 

Cette version reste correcte, mais elle continue à comparer les éléments après avoir trouvé la valeur. Lorsque seule l’existence ou la première position est demandée, un arrêt anticipé évite des opérations inutiles.

13.1.3 Arrêt dès que l’élément est trouvé

L’arrêt anticipé termine la recherche à la première occurrence. Il améliore le comportement dans les cas favorables, notamment lorsque la valeur se trouve près du début du tableau.

Version avec boucle TantQue

Fonction RechercherPremier(T : Tableau, n : Entier, x : Réel) : Entier
Variables
    i : Entier
Début
    i ← 0
    TantQue i < n ET T[i] ≠ x Faire
        i ← i + 1
    FinTantQue

    Si i < n Alors
        Retourner i
    Sinon
        Retourner -1
    FinSi
Fin

 

Ordre de la condition : il faut vérifier i < n avant d’accéder à T[i]. Lorsque i = n, l’indice est en dehors du tableau.

Tableau T

Clé x

Comparaisons

Résultat

[8, 3, 12, 5, 9]810
[8, 3, 12, 5, 9]543
[8, 3, 12, 5, 9]954
[8, 3, 12, 5, 9]75-1
[]70-1

13.1.4 Table de trace détaillée

Considérons T = [14, 7, 22, 7, 31] et x = 22. La boucle s’arrête lorsque l’indice 2 est atteint.

Itération

i avant test

i < n

T[i] ≠ 22

Action

10Vrai14 ≠ 22 : Vraii ← 1
21Vrai7 ≠ 22 : Vraii ← 2
32Vrai22 ≠ 22 : FauxSortie de la boucle
Après la boucle22 < 5 : VraiRetourner 2

La valeur 7 apparaît deux fois, mais une recherche de la première occurrence retourne l’indice 1 et ne poursuit pas jusqu’à l’indice 3.

13.1.5 Recherche de toutes les occurrences

Lorsque le tableau peut contenir des doublons, la première occurrence ne suffit pas toujours. Il faut alors parcourir tout le tableau et traiter chaque égalité.

Afficher toutes les positions

Procédure AfficherOccurrences(T : Tableau, n : Entier, x : Réel)
Variables
    i, compteur : Entier
Début
    compteur ← 0
    Pour i allant de 0 à n - 1 Faire
        Si T[i] = x Alors
            Afficher("Occurrence à l’indice ", i)
            compteur ← compteur + 1
        FinSi
    FinPour

    Si compteur = 0 Alors
        Afficher("Valeur absente")
    Sinon
        Afficher("Nombre d’occurrences : ", compteur)
    FinSi
Fin

 

Indice

0

1

2

3

4

5

T

4

9

4

2

4

7

T[i] = 4 ?

Oui

Non

Oui

Non

Oui

Non

Les occurrences de 4 se trouvent aux indices 0, 2 et 4. Le compteur final vaut 3.

13.1.6 Retourner les positions dans un tableau

Si les positions doivent être réutilisées, elles peuvent être enregistrées dans un second tableau. Celui-ci possède au maximum n éléments, puisque chaque case du tableau d’origine peut correspondre à une occurrence.

Construire le tableau des positions

Fonction Positions(T : Tableau, n : Entier, x : Réel,
                   P : Tableau) : Entier
Variables
    i, k : Entier
Début
    k ← 0
    Pour i allant de 0 à n - 1 Faire
        Si T[i] = x Alors
            P[k] ← i
            k ← k + 1
        FinSi
    FinPour
    Retourner k
Fin

// Les positions valides sont P[0] à P[k - 1].

 

Remarque : la fonction retourne le nombre de positions écrites. Ce nombre permet de distinguer la partie utile du tableau P de sa capacité totale.

13.1.7 Recherche à partir d’une position

Dans certaines applications, on souhaite chercher la prochaine occurrence après une position donnée. Le point de départ devient alors un paramètre.

Rechercher à partir de debut

Fonction RechercherDepuis(T : Tableau, n : Entier,
                          x : Réel, debut : Entier) : Entier
Variables
    i : Entier
Début
    Si debut < 0 OU debut > n Alors
        Retourner -1
    FinSi

    i ← debut
    TantQue i < n ET T[i] ≠ x Faire
        i ← i + 1
    FinTantQue

    Si i < n Alors
        Retourner i
    Sinon
        Retourner -1
    FinSi
Fin

 

Cette fonction peut être appelée plusieurs fois afin de parcourir les occurrences successives sans recommencer systématiquement à l’indice 0.

13.1.8 Recherche avec sentinelle

La technique de la sentinelle place temporairement la valeur recherchée dans une case supplémentaire située après la partie utile du tableau. Elle simplifie la condition de boucle, mais elle exige une capacité disponible et la restauration éventuelle de la case utilisée.

Principe de la sentinelle

Fonction RechercheSentinelle(T : Tableau, n : Entier, x : Réel) : Entier
Variables
    i : Entier
Début
    T[n] ← x          // Une case supplémentaire doit exister.
    i ← 0
    TantQue T[i] ≠ x Faire
        i ← i + 1
    FinTantQue

    Si i < n Alors
        Retourner i
    Sinon
        Retourner -1
    FinSi
Fin

 

Cette variante est présentée pour la culture algorithmique. Dans un programme réel, elle doit être utilisée avec prudence afin de ne pas écrire en dehors de la capacité du tableau.

13.1.9 Version récursive

Une recherche séquentielle peut aussi être formulée récursivement. Le paramètre i indique la prochaine case à examiner.

Recherche séquentielle récursive

Fonction RechercheSeqRec(T : Tableau, n : Entier,
                         x : Réel, i : Entier) : Entier
Début
    Si i = n Alors
        Retourner -1
    SinonSi T[i] = x Alors
        Retourner i
    Sinon
        Retourner RechercheSeqRec(T, n, x, i + 1)
    FinSi
Fin

// Appel initial : RechercheSeqRec(T, n, x, 0)

 

Cette version réalise les mêmes comparaisons que la version itérative, mais elle utilise un appel de fonction par élément examiné. La boucle est généralement plus adaptée à ce problème simple.

13.1.10 Cas particuliers et validation

Situation

Comportement attendu

Tableau videRetourner -1, Faux ou 0 selon le résultat demandé.
Valeur au premier indiceArrêt après une seule comparaison.
Valeur au dernier indiceExamen de toutes les cases.
Valeur absenteExamen de toutes les cases.
Plusieurs occurrencesPréciser si l’on cherche la première, la dernière ou toutes.
n supérieur à la capacitéEntrée incorrecte à refuser.
Types incompatiblesLa comparaison doit être définie pour les valeurs concernées.
Contrat recommandé : 0 ≤ n ≤ capacité du tableau. La valeur x doit être comparable aux éléments de T.

13.2 Recherche dichotomique

13.2.1 Principe de division de l’espace de recherche

La recherche dichotomique, aussi appelée recherche binaire, exploite l’ordre des données. Elle compare la clé à l’élément situé au milieu de la zone encore possible. Selon le résultat, elle conserve la moitié gauche ou la moitié droite et élimine l’autre moitié.

L’espace de recherche est donc approximativement divisé par deux à chaque étape. Une grande quantité de données peut être éliminée après très peu de comparaisons.

Comparaison avec T[milieu]

Conclusion

Nouvelle zone

x = T[milieu]La valeur est trouvée.Arrêt
x < T[milieu]x ne peut pas être à droite.gauche à milieu - 1
x > T[milieu]x ne peut pas être à gauche.milieu + 1 à droite

13.2.2 Condition indispensable : tableau trié

La décision d’éliminer une moitié repose sur l’ordre du tableau. Dans un tableau trié par ordre croissant, toutes les valeurs situées à gauche du milieu sont inférieures ou égales à l’élément central, tandis que celles de droite sont supérieures ou égales.

Si le tableau n’est pas trié, une valeur plus petite que l’élément central peut se trouver à droite. L’élimination d’une moitié n’est alors plus justifiée et l’algorithme peut conclure à tort que la valeur est absente.

Tableau

Trié ?

Recherche dichotomique correcte ?

[2, 5, 8, 12, 19, 24]Oui, croissantOui
[24, 19, 12, 8, 5, 2]Oui, décroissantOui, avec comparaisons adaptées
[2, 19, 5, 24, 8, 12]NonNon
[3, 3, 4, 4, 4, 9]Oui, avec doublonsOui, mais l’occurrence trouvée n’est pas forcément la première
Point essentiel : trier uniquement pour effectuer une seule petite recherche peut coûter plus cher qu’une recherche séquentielle. Le tri devient intéressant lorsque les données restent ordonnées ou lorsque de nombreuses recherches sont prévues.

13.2.3 Bornes de la zone de recherche

La version présentée utilise un intervalle fermé : les indices gauche et droite appartiennent tous les deux à la zone encore possible. Au départ, gauche = 0 et droite = n - 1. La zone est vide lorsque gauche > droite.

Variable

Signification

Valeur initiale

gauchePremier indice encore possible0
droiteDernier indice encore possiblen - 1
milieuIndice central de la zone(gauche + droite) DIV 2

Il existe aussi des formulations utilisant un intervalle semi-ouvert [gauche, droite[. Elles sont correctes si les conditions et mises à jour restent cohérentes. Mélanger les deux conventions produit fréquemment des erreurs.

13.2.4 Calcul de l’indice du milieu

Avec des indices entiers, le milieu est calculé par division entière. La formule simple est : milieu ← (gauche + droite) DIV 2.

Formule recommandée dans les langages à entiers bornés

milieu ← gauche + (droite - gauche) DIV 2

 

Cette seconde écriture évite que l’addition gauche + droite dépasse la valeur maximale du type entier lorsque les indices sont très grands. Dans le cadre des exercices, les deux formules donnent le même indice.

gauche

droite

(gauche + droite) DIV 2

Zone

0849 éléments
0738 éléments
4966 éléments
5551 élément

13.2.5 Mise à jour des bornes

Après une comparaison infructueuse, l’élément du milieu est exclu de la nouvelle zone, puisqu’il vient d’être vérifié. Il faut donc utiliser milieu - 1 ou milieu + 1. Réutiliser milieu sans le dépasser peut empêcher la zone de diminuer et provoquer une boucle infinie.

Règles de mise à jour

Si x < T[milieu] Alors
    droite ← milieu - 1
Sinon
    gauche ← milieu + 1
FinSi

 

Erreur fréquente : écrire droite ← milieu ou gauche ← milieu peut conserver exactement la même zone lorsque deux indices seulement restent à examiner.

13.2.6 Version itérative

Recherche dichotomique itérative

Fonction RechercheDichotomique(T : Tableau, n : Entier,
                                x : Réel) : Entier
Variables
    gauche, droite, milieu : Entier
Début
    gauche ← 0
    droite ← n - 1

    TantQue gauche ≤ droite Faire
        milieu ← gauche + (droite - gauche) DIV 2

        Si T[milieu] = x Alors
            Retourner milieu
        SinonSi x < T[milieu] Alors
            droite ← milieu - 1
        Sinon
            gauche ← milieu + 1
        FinSi
    FinTantQue

    Retourner -1
Fin

 

Le retour immédiat simplifie la lecture : dès que l’égalité est rencontrée, aucune autre comparaison n’est nécessaire. Si la boucle se termine, la zone est vide et la valeur est absente.

13.2.7 Traçage d’une recherche réussie

Considérons le tableau trié T = [3, 6, 9, 12, 15, 18, 21, 24, 27] et la recherche de x = 21.

Étape

gauche

droite

milieu

T[milieu]

Décision

10841521 > 15 : gauche ← 5
258621Valeur trouvée à l’indice 6

Seules deux comparaisons principales sont nécessaires, alors qu’une recherche séquentielle depuis le début aurait examiné sept éléments.

13.2.8 Traçage d’une recherche infructueuse

Recherchons maintenant x = 20 dans le même tableau.

Étape

gauche

droite

milieu

T[milieu]

Décision

10841520 > 15 : gauche ← 5
25862120 < 21 : droite ← 5
35551820 > 18 : gauche ← 6
Fin65gauche > droite : retourner -1

L’intervalle devient vide sans que toutes les cases soient examinées. L’ordre du tableau permet de conclure que 20 ne peut se trouver ailleurs.

13.2.9 Version récursive

La version récursive reçoit les bornes de la zone courante. Son cas de base d’échec correspond à gauche > droite. Chaque appel réduit la taille de l’intervalle.

Recherche dichotomique récursive

Fonction RechercheDichoRec(T : Tableau, x : Réel,
                            gauche, droite : Entier) : Entier
Variables
    milieu : Entier
Début
    Si gauche > droite Alors
        Retourner -1
    FinSi

    milieu ← gauche + (droite - gauche) DIV 2

    Si T[milieu] = x Alors
        Retourner milieu
    SinonSi x < T[milieu] Alors
        Retourner RechercheDichoRec(T, x, gauche, milieu - 1)
    Sinon
        Retourner RechercheDichoRec(T, x, milieu + 1, droite)
    FinSi
Fin

// Appel initial : RechercheDichoRec(T, x, 0, n - 1)

 

Élément récursif

Interprétation

Cas de basegauche > droite : la zone est vide.
Cas de réussiteT[milieu] = x.
Progression à gaucheLa borne droite devient milieu - 1.
Progression à droiteLa borne gauche devient milieu + 1.
Mesure qui diminueNombre d’indices compris entre gauche et droite.

13.2.10 Tableau contenant des doublons

Une recherche dichotomique classique retourne une occurrence quelconque. Pour trouver la première occurrence, il faut continuer la recherche dans la moitié gauche même après une égalité. Pour trouver la dernière, on continue dans la moitié droite.

Première occurrence par recherche dichotomique

Fonction PremiereOccurrence(T : Tableau, n : Entier,
                            x : Réel) : Entier
Variables
    gauche, droite, milieu, resultat : Entier
Début
    gauche ← 0
    droite ← n - 1
    resultat ← -1

    TantQue gauche ≤ droite Faire
        milieu ← gauche + (droite - gauche) DIV 2
        Si T[milieu] = x Alors
            resultat ← milieu
            droite ← milieu - 1
        SinonSi x < T[milieu] Alors
            droite ← milieu - 1
        Sinon
            gauche ← milieu + 1
        FinSi
    FinTantQue

    Retourner resultat
Fin

 

Tableau

x

Recherche classique

Première occurrence

[2, 4, 4, 4, 7, 9]4Peut retourner 2 ou un autre indice égalRetourne 1
[1, 1, 1, 1]1Occurrence quelconqueRetourne 0
[2, 4, 6]5-1-1

13.2.11 Recherche dans un tableau trié décroissant

La méthode reste applicable à un tableau trié par ordre décroissant, mais les décisions doivent être inversées. Si x est inférieur à T[milieu], il faut chercher à droite, là où se trouvent les valeurs plus petites.

Règle pour un ordre décroissant

Si T[milieu] = x Alors
    Retourner milieu
SinonSi x < T[milieu] Alors
    gauche ← milieu + 1
Sinon
    droite ← milieu - 1
FinSi

 

Cohérence de l’ordre : la fonction de comparaison utilisée par la recherche doit être la même que celle utilisée pour trier le tableau.

13.2.12 Erreurs fréquentes

Erreur

Conséquence

Correction

Appliquer l’algorithme à un tableau non triéRésultat incorrect possible.Vérifier ou garantir le tri.
Initialiser droite à nAccès possible à T[n], hors limites.Utiliser droite ← n - 1 pour un intervalle fermé.
Utiliser gauche < droiteLa dernière case peut ne pas être testée.Utiliser gauche ≤ droite.
Ne pas exclure milieuLa zone peut ne plus diminuer.Employer milieu - 1 ou milieu + 1.
Mélanger ordre croissant et décroissantMauvaise moitié conservée.Adapter les comparaisons à l’ordre.
Supposer que l’occurrence trouvée est la premièreRésultat insuffisant avec doublons.Utiliser une variante dédiée.

13.3 Comparaison des méthodes

13.3.1 Nombre d’opérations

L’opération principale est la comparaison entre la clé et un élément du tableau. Le nombre de comparaisons dépend de la position de la valeur, de son absence éventuelle et de la méthode utilisée.

Méthode

Cas favorable

Cas défavorable

Idée de croissance

Recherche séquentielle1 comparaisonn comparaisonsLe travail peut croître proportionnellement à n.
Recherche dichotomique1 comparaisonEnviron log₂(n) + 1 comparaisonsLa zone est divisée par deux.

La notation O(n) pour la recherche séquentielle et O(log n) pour la recherche dichotomique sera approfondie dans le chapitre consacré à la complexité. À ce stade, il suffit de retenir que doubler la taille double approximativement le pire travail séquentiel, tandis qu’il ajoute environ une étape à la recherche dichotomique.

Nombre d’éléments n

Maximum séquentiel

Maximum dichotomique approximatif

884
16165
32326
1 0241 02411
1 000 0001 000 000Environ 20

13.3.2 Influence de la taille des données

Pour un très petit tableau, la simplicité de la recherche séquentielle peut être suffisante. Lorsque le nombre d’éléments devient important et que le tableau est déjà trié, la recherche dichotomique réduit fortement le nombre de comparaisons.

La taille ne doit toutefois pas être considérée seule. Le coût de préparation des données, leur fréquence de modification et le nombre de recherches prévues influencent le choix.

Situation

Analyse

Petit tableau, une seule rechercheLa recherche séquentielle est souvent suffisante.
Grand tableau déjà triéLa recherche dichotomique est très avantageuse.
Grand tableau non trié, une seule rechercheParcourir séquentiellement évite le coût d’un tri préalable.
Grand tableau, nombreuses recherchesTrier une fois puis utiliser la dichotomie peut être rentable.
Tableau modifié fréquemmentMaintenir l’ordre peut entraîner un coût d’insertion ou de tri.

13.3.3 Tableau trié ou non trié

Caractéristique des données

Recherche séquentielle

Recherche dichotomique

Tableau non triéApplicableNon applicable correctement
Tableau trié croissantApplicableApplicable
Tableau trié décroissantApplicableApplicable avec comparaisons adaptées
Données avec doublonsTrouve facilement toutes les occurrencesVariante nécessaire pour première ou dernière occurrence
Ordre inconnuChoix sûrLe tri doit être garanti avant utilisation
Règle de choix : en l’absence de garantie sur l’ordre, la recherche séquentielle est la méthode correcte par défaut.

13.3.4 Cas favorable et cas défavorable

Méthode

Cas favorable

Cas défavorable

SéquentielleLa valeur est en première position.La valeur est absente ou en dernière position.
DichotomiqueLa valeur se trouve immédiatement au milieu.La valeur est atteinte au dernier niveau ou est absente.

Le cas moyen dépend de la distribution des recherches et de la probabilité que chaque élément soit demandé. Dans un tableau non trié où toutes les positions sont aussi probables, une recherche séquentielle réussie examine en moyenne environ la moitié des éléments.

13.3.5 Mémoire utilisée

Les versions itératives utilisent seulement quelques variables supplémentaires : un indice pour la recherche séquentielle et trois indices pour la recherche dichotomique. Leur mémoire auxiliaire reste donc constante.

Les versions récursives créent une pile d’appels. Une recherche séquentielle récursive peut empiler jusqu’à n appels, tandis qu’une recherche dichotomique récursive n’en empile qu’un nombre proportionnel au nombre de divisions successives.

Version

Mémoire auxiliaire qualitative

Séquentielle itérativeConstante
Séquentielle récursivePeut croître jusqu’au nombre d’éléments
Dichotomique itérativeConstante
Dichotomique récursiveCroît lentement avec le nombre de divisions

13.3.6 Coût global : trier puis rechercher

La recherche dichotomique ne doit pas être évaluée isolément lorsque les données sont initialement non triées. Il faut aussi considérer le coût du tri. Pour une seule recherche, trier tout le tableau peut être inutile. Pour des centaines de recherches sur les mêmes données, le tri initial peut être amorti.

Scénario

Stratégie raisonnable

Une recherche dans des données non triéesRecherche séquentielle.
Plusieurs recherches, données rarement modifiéesTrier puis utiliser la recherche dichotomique.
Données ajoutées en permanence sans maintien de l’ordreRecherche séquentielle ou structure spécialisée.
Données maintenues triées à chaque insertionRecherche dichotomique, en tenant compte du coût des insertions.

13.3.7 Tableau de décision

Question

Oui

Non

Le tableau est-il garanti trié ?Examiner la dichotomie.Utiliser la recherche séquentielle ou trier.
Une seule recherche est-elle prévue ?La simplicité peut primer.Le coût d’organisation peut être amorti.
Faut-il toutes les occurrences ?Prévoir une variante ou un parcours complémentaire.La première occurrence peut suffire.
Les données changent-elles souvent ?Évaluer le coût de maintien du tri.Le tri initial reste durable.
Le tableau est-il très grand ?L’écart entre les méthodes devient important.Les deux méthodes peuvent convenir.

Applications guidées

Application 1 — Rechercher un étudiant par matricule

Un tableau Matricules contient les identifiants des étudiants dans l’ordre d’inscription, sans garantie de tri. Concevoir une fonction qui retourne l’indice d’un matricule demandé.

Solution adaptée

Fonction ChercherMatricule(Matricules : Tableau,
                            n : Entier, cible : Chaîne) : Entier
Variables
    i : Entier
Début
    i ← 0
    TantQue i < n ET Matricules[i] ≠ cible Faire
        i ← i + 1
    FinTantQue
    Si i < n Alors
        Retourner i
    Sinon
        Retourner -1
    FinSi
Fin

 

La recherche séquentielle est choisie parce que le tableau n’est pas garanti trié.

Application 2 — Rechercher une note dans une liste triée

Les notes ont été classées par ordre croissant. On souhaite déterminer rapidement si la note 14,5 est présente.

Solution adaptée

position ← RechercheDichotomique(NotesTriees, n, 14.5)
Si position = -1 Alors
    Afficher("Note absente")
Sinon
    Afficher("Note trouvée à l’indice ", position)
FinSi

 

La recherche dichotomique est pertinente, car l’ordre est connu et permet d’éliminer une moitié à chaque étape.

Application 3 — Compter les absences

Un tableau de caractères contient P pour présent et A pour absent. Il faut compter toutes les absences. Un arrêt à la première occurrence serait incorrect.

Parcours complet

Fonction CompterAbsences(Presences : Tableau, n : Entier) : Entier
Variables
    i, nombre : Entier
Début
    nombre ← 0
    Pour i allant de 0 à n - 1 Faire
        Si Presences[i] = 'A' Alors
            nombre ← nombre + 1
        FinSi
    FinPour
    Retourner nombre
Fin

 

Application 4 — Première et dernière occurrence

Dans T = [1, 2, 2, 2, 2, 5, 9], déterminer les indices de la première et de la dernière occurrence de 2. Deux recherches dichotomiques modifiées permettent d’obtenir les bornes du bloc de doublons.

Dernière occurrence

Fonction DerniereOccurrence(T : Tableau, n : Entier, x : Réel) : Entier
Variables
    g, d, m, resultat : Entier
Début
    g ← 0
    d ← n - 1
    resultat ← -1
    TantQue g ≤ d Faire
        m ← g + (d - g) DIV 2
        Si T[m] = x Alors
            resultat ← m
            g ← m + 1
        SinonSi x < T[m] Alors
            d ← m - 1
        Sinon
            g ← m + 1
        FinSi
    FinTantQue
    Retourner resultat
Fin

 

La première occurrence vaut 1 et la dernière vaut 4. Le nombre d’occurrences est donc 4 - 1 + 1 = 4.

Application 5 — Point d’insertion dans un tableau trié

Même lorsque x est absent, la dichotomie peut déterminer l’indice où x devrait être inséré afin de préserver l’ordre. À la fin de la boucle, la borne gauche indique cette position.

Indice d’insertion

Fonction PositionInsertion(T : Tableau, n : Entier, x : Réel) : Entier
Variables
    gauche, droite, milieu : Entier
Début
    gauche ← 0
    droite ← n - 1
    TantQue gauche ≤ droite Faire
        milieu ← gauche + (droite - gauche) DIV 2
        Si T[milieu] < x Alors
            gauche ← milieu + 1
        Sinon
            droite ← milieu - 1
        FinSi
    FinTantQue
    Retourner gauche
Fin

 

T

x

Position retournée

[3, 8, 12, 20]10
[3, 8, 12, 20]102
[3, 8, 12, 20]122
[3, 8, 12, 20]254

Méthode de résolution et de traçage

Méthode pour une recherche séquentielle

1.  Préciser le résultat demandé : existence, position, compteur ou toutes les positions.

2.  Déterminer si un arrêt anticipé est autorisé.

3.  Initialiser l’indice et les éventuels compteurs.

4.  Contrôler la borne avant chaque accès au tableau.

5.  Comparer l’élément courant à la clé.

6.  Mettre à jour l’indice ou le résultat.

7.  Traiter clairement le cas où la valeur est absente.

Méthode pour une recherche dichotomique

1.  Vérifier que le tableau est trié et connaître le sens du tri.

2.  Choisir une convention d’intervalle et la conserver.

3.  Initialiser gauche et droite.

4.  Calculer le milieu par division entière.

5.  Comparer la clé à l’élément central.

6.  Exclure le milieu et conserver une seule moitié.

7.  Répéter tant que la zone n’est pas vide.

8.  Tester les cas à zéro, un et deux éléments.

Erreurs fréquentes et bonnes pratiques

Erreur fréquente

Pourquoi elle est problématique

Bonne pratique

Ne pas préciser le résultat recherchéPremière occurrence et toutes les occurrences exigent des algorithmes différents.Écrire le contrat avant le pseudo-code.
Accéder à T[i] avant de tester i < nRisque d’accès hors limites.Tester la borne en premier dans une conjonction.
Continuer après une première occurrence inutilementComparaisons supplémentaires.Utiliser un arrêt anticipé.
Arrêter lors du comptage des occurrencesLe compteur devient incomplet.Parcourir tout le tableau.
Utiliser la dichotomie sans tri garantiRésultat potentiellement faux.Documenter la précondition de tri.
Mauvaise initialisation de droiteLa zone inclut un indice inexistant.Avec un intervalle fermé, droite = n - 1.
Mise à jour qui conserve le milieuBoucle infinie possible.Exclure le milieu déjà comparé.
Oublier les doublonsL’indice obtenu peut ne pas être la première occurrence.Utiliser la variante adaptée.

Travaux dirigés

Pour chaque exercice, préciser les préconditions, le résultat retourné, le pseudo-code et au moins quatre jeux d’essai incluant un cas limite.

Exercice 1 — Présence et position

Écrire deux fonctions de recherche séquentielle dans un tableau d’entiers : la première retourne un booléen indiquant si x existe ; la seconde retourne l’indice de sa première occurrence ou -1.

Exercice 2 — Dernière occurrence séquentielle

Écrire une fonction qui retourne la dernière occurrence de x dans un tableau non trié. Proposer une version parcourant le tableau de gauche à droite, puis une version partant de la fin.

Exercice 3 — Toutes les positions

Construire un tableau P contenant les indices de toutes les occurrences de x dans T. La fonction retourne le nombre d’indices écrits dans P.

Exercice 4 — Recherche parmi des noms

Un tableau contient des noms. Écrire une recherche qui ne distingue pas les majuscules des minuscules. Exemple : « AMAL » et « Amal » doivent être considérés comme égaux.

Exercice 5 — Trace dichotomique

Tracer la recherche des valeurs 4, 26 et 17 dans le tableau trié [2, 4, 7, 11, 15, 18, 21, 26, 30]. Indiquer gauche, droite, milieu et décision à chaque étape.

Exercice 6 — Corriger les bornes

L’algorithme suivant contient plusieurs erreurs. Les identifier et proposer une version correcte.

gauche ← 0
droite ← n
TantQue gauche < droite Faire
    milieu ← (gauche + droite) DIV 2
    Si T[milieu] = x Alors
        Retourner milieu
    SinonSi x < T[milieu] Alors
        droite ← milieu
    Sinon
        gauche ← milieu
    FinSi
FinTantQue
Retourner -1

 

Exercice 7 — Première occurrence dichotomique

Écrire et tracer une fonction qui retourne la première occurrence de x dans un tableau trié contenant des doublons.

Exercice 8 — Nombre d’occurrences par deux recherches

Dans un tableau trié, calculer le nombre d’occurrences de x à partir de sa première et de sa dernière occurrence. Éviter un parcours complet du bloc de doublons.

Exercice 9 — Comparaison expérimentale

Pour des tableaux de tailles 8, 16, 32 et 64, compter les comparaisons réalisées par les deux méthodes lorsque la valeur est absente. Présenter les résultats dans un tableau et commenter leur évolution.

Exercice 10 — Choix de méthode

Choisir et justifier une méthode pour chacune des situations suivantes : une liste non triée de 20 noms ; un annuaire trié de 100 000 noms ; une seule recherche dans un fichier non trié ; 10 000 recherches dans une liste stable ; comptage de toutes les valeurs égales à 0.

Corrigés indicatifs

Corrigé 1 — Présence et position

Fonction ExisteSeq(T : Tableau, n, x : Entier) : Booléen
Début
    Retourner RecherchePremierSeq(T, n, x) ≠ -1
Fin

Fonction RecherchePremierSeq(T : Tableau, n, x : Entier) : Entier
Variables
    i : Entier
Début
    i ← 0
    TantQue i < n ET T[i] ≠ x Faire
        i ← i + 1
    FinTantQue
    Si i < n Alors
        Retourner i
    Sinon
        Retourner -1
    FinSi
Fin

 

Corrigé 2 — Dernière occurrence séquentielle

Version depuis la fin

Fonction DerniereSeq(T : Tableau, n, x : Entier) : Entier
Variables
    i : Entier
Début
    i ← n - 1
    TantQue i ≥ 0 ET T[i] ≠ x Faire
        i ← i - 1
    FinTantQue
    Retourner i
Fin

 

Lorsque la valeur est absente, i devient -1. Le parcours depuis la fin permet un arrêt dès que la dernière occurrence est rencontrée.

Corrigé 3 — Toutes les positions

Fonction ToutesPositions(T : Tableau, n, x : Entier,
                          P : Tableau) : Entier
Variables
    i, k : Entier
Début
    k ← 0
    Pour i allant de 0 à n - 1 Faire
        Si T[i] = x Alors
            P[k] ← i
            k ← k + 1
        FinSi
    FinPour
    Retourner k
Fin

 

Corrigé 4 — Recherche parmi des noms

Fonction ChercherNom(Noms : Tableau, n : Entier,
                    cible : Chaîne) : Entier
Variables
    i : Entier
    cibleNormalisee : Chaîne
Début
    cibleNormalisee ← Minuscules(cible)
    i ← 0
    TantQue i < n ET Minuscules(Noms[i]) ≠ cibleNormalisee Faire
        i ← i + 1
    FinTantQue
    Si i < n Alors
        Retourner i
    Sinon
        Retourner -1
    FinSi
Fin

 

Dans une application réelle, il est souvent préférable de normaliser les noms une seule fois au moment du stockage plutôt qu’à chaque comparaison.

Corrigé 5 — Trace dichotomique

Valeur

Étapes principales

Résultat

4m=4 → 15 ; m=1 → 4Indice 1
26m=4 → 15 ; m=6 → 21 ; m=7 → 26Indice 7
17m=4 → 15 ; m=6 → 21 ; m=5 → 18 ; zone vide-1

Corrigé 6 — Corriger les bornes

Les erreurs sont : droite initialisée à n au lieu de n - 1, condition gauche < droite qui peut ignorer la dernière case et mises à jour qui peuvent conserver le milieu.

Version corrigée

gauche ← 0
droite ← n - 1
TantQue gauche ≤ droite Faire
    milieu ← gauche + (droite - gauche) DIV 2
    Si T[milieu] = x Alors
        Retourner milieu
    SinonSi x < T[milieu] Alors
        droite ← milieu - 1
    Sinon
        gauche ← milieu + 1
    FinSi
FinTantQue
Retourner -1

 

Corrigé 7 — Première occurrence dichotomique

Fonction PremiereDicho(T : Tableau, n, x : Entier) : Entier
Variables
    g, d, m, resultat : Entier
Début
    g ← 0
    d ← n - 1
    resultat ← -1
    TantQue g ≤ d Faire
        m ← g + (d - g) DIV 2
        Si T[m] = x Alors
            resultat ← m
            d ← m - 1
        SinonSi x < T[m] Alors
            d ← m - 1
        Sinon
            g ← m + 1
        FinSi
    FinTantQue
    Retourner resultat
Fin

 

Corrigé 8 — Nombre d’occurrences

premiere ← PremiereDicho(T, n, x)
Si premiere = -1 Alors
    Retourner 0
Sinon
    derniere ← DerniereOccurrence(T, n, x)
    Retourner derniere - premiere + 1
FinSi

 

La formule est valable parce que les occurrences d’une même valeur sont contiguës dans un tableau trié.

Corrigé 9 — Comparaison expérimentale

n

Séquentielle, valeur absente

Dichotomique, maximum approximatif

88 comparaisons4 comparaisons
1616 comparaisons5 comparaisons
3232 comparaisons6 comparaisons
6464 comparaisons7 comparaisons

Quand n double, le pire cas séquentiel double. Pour la dichotomie, une seule étape supplémentaire suffit approximativement.

Corrigé 10 — Choix de méthode

Situation

Choix

Justification

20 noms non triésSéquentiellePetit tableau et absence de tri.
100 000 noms triésDichotomiqueOrdre garanti et grand volume.
Une seule recherche non triéeSéquentielleÉvite de trier tout le tableau.
10 000 recherches, liste stableTrier puis dichotomieLe coût du tri est amorti.
Compter toutes les valeurs 0Parcours completToutes les occurrences doivent être examinées, sauf variante sur tableau trié.

Synthèse du chapitre

La recherche séquentielle est universelle et simple : elle examine les éléments dans leur ordre de stockage. Elle est adaptée aux données non triées, aux petits tableaux et aux traitements qui nécessitent toutes les occurrences. La recherche dichotomique est beaucoup plus rapide sur les grandes données triées, car elle divise la zone possible par deux à chaque étape.

Notion

À retenir

Clé de rechercheValeur que l’on souhaite localiser.
Recherche séquentielleParcours élément par élément, sans précondition de tri.
Arrêt anticipéPossible lorsque la première occurrence suffit.
Toutes les occurrencesExigent généralement un parcours complet.
Recherche dichotomiqueDivision répétée d’un intervalle trié.
Bornesgauche et droite délimitent la zone encore possible.
MilieuIndice utilisé pour choisir la moitié à conserver.
Condition de triIndispensable pour justifier l’élimination d’une moitié.
DoublonsUne variante est nécessaire pour la première ou la dernière occurrence.
Choix de méthodeDépend de l’ordre, de la taille, des modifications et du nombre de recherches.

Checklist de conception

1.  Définir précisément ce que doit retourner la recherche.

2.  Identifier la taille utile du tableau et valider les bornes.

3.  Vérifier si l’ordre des données est garanti.

4.  Choisir entre parcours complet et arrêt anticipé.

5.  Traiter explicitement le tableau vide et la valeur absente.

6.  Pour la dichotomie, fixer une convention d’intervalle.

7.  Exclure le milieu après chaque comparaison infructueuse.

8.  Tester une zone de un puis de deux éléments.

9.  Traiter les doublons selon le besoin.

10.  Comparer le coût global, y compris un éventuel tri préalable.

Glossaire

Terme

Définition

CléValeur recherchée dans un ensemble de données.
OccurrenceApparition d’une valeur dans le tableau.
Recherche séquentielleMéthode examinant successivement les éléments.
Arrêt anticipéFin de l’algorithme dès que le résultat suffisant est obtenu.
Recherche dichotomiqueMéthode divisant une zone triée en deux parties.
Borne gauchePremier indice encore susceptible de contenir la clé.
Borne droiteDernier indice encore susceptible de contenir la clé.
MilieuIndice central de la zone de recherche.
Tableau triéTableau dont les éléments respectent un ordre défini.
SentinelleValeur placée temporairement pour simplifier une condition d’arrêt.


 

 

Auto-évaluation

Compétence

Acquise

À renforcer

Je sais écrire une recherche séquentielle avec arrêt anticipé.

Je sais compter et enregistrer toutes les occurrences.

Je sais expliquer pourquoi la dichotomie exige un tableau trié.

Je sais initialiser et mettre à jour les bornes.

Je sais tracer une recherche dichotomique.

Je sais écrire les versions itérative et récursive.

Je sais gérer les doublons.

Je sais choisir la méthode adaptée à une situation.

Conclusion : un bon algorithme de recherche repose sur un contrat clair, des bornes correctes et une méthode compatible avec l’organisation des données.