====== Recherche dichotomique ======
Considérons un tableau ''T'' et une valeur ''needle'' que l'on souhaite trouver dans le tableau.
La recherche dichotomique nécessite que ''T'' soit **trié**. Dit autrement, **Précondition :** ''T'' est trié.
L'algorithme de recherche dichotomique est à connaître.
===== Algorithme =====
ENTRÉES : T, needle
DÉBUT
a = 0 et b = dernier indice de T
TANT QUE a < b FAIRE
m = indice au milieu de a et b, arrondi par défaut au besoin
SI valeur en m >= needle ALORS
continuer la recherche à gauche : b prend la valeur m
SINON
continuer la recherche à droite : a prend la valeur m + 1
FIN SI
FIN TANT QUE
SI valeur en a est needle ALORS
RENVOYER a
SINON
RENVOYER -1
FIN SI
FIN
Implémentez en Python la fonction ''%%recherche_dichotomique(T, needle)%%'' faisant la traduction de cet algorithme.
Ajoutez les tests suivants
T = [1, 5, 13, 15, 15, 41, 43, 58, 58, 75, 89, 101]
assert recherche_dichotomique(T, 22) == -1
assert recherche_dichotomique(T, 41) == 5
assert recherche_dichotomique(T, 15) == 3
assert recherche_dichotomique(T, 58) == 7
assert recherche_dichotomique(T, 122) == -1
assert recherche_dichotomique(T, 0) == -1
assert recherche_dichotomique([], 45) == -1
===== Correction =====
Les tests précédents nous invitent à croire que la fonction est correcte. Mais comment être certain que c'est le cas pour n'importe quel tableau ?
==== Terminaison ====
La fonction contient une boucle ''TANT QUE''. C'est le seul élément à problème. Nous devons nous assurer que la condition de cette boucle finit devenir fausse de sorte que la boucle se termine.
Pour cela, on considère une quantité et on vérifie que cette quantité change toujours dans le même sens.
* Justifiez que la quantité ''%%b - a%%'' diminue d'au moins 1 à chaque répétition de la boucle ''while''.
* Déduisez-en que la boucle se termine.
La quantité ''%%b - a%%'' qui nous a aidé dans ce raisonnement est appelée **variant de boucle**.
==== Correction ====
* Que se passe-t-il si ''T'' est vide ?
* Comment corriger ce problème ?
Cela vous montre qu'on peut facilement oublier des cas à problème. Il faut toujours réfléchir à ces cas limites.
Supposons maintenant que le problème précédent à été résolu.
On considère la portion de ''T'' allant des indices ''a'' à ''b'' inclus. On peut la noter ''Tab''.
* Justifiez qu'au début de l'algorithme, ''T'' et ''Tab'' sont identiques.
* Justifiez que si ''needle'' est dans ''Tab'' au début d'un tour d'exécution de ''while'', alors ''needle'' est toujours dans ''Tab'' à la fin de l'exécution.
* À quoi se réduit ''Tab'' en fin de boucle ?
* Justifiez que la fonction est correcte.
On adopte ici un raisonnement assez rigoureux pour être convainquant. On pourrait aller plus loin et utiliser un langage aussi rigoureux qu'une démonstration mathématique. Tous les programmeurs ne font pas ce travail. Beaucoup de logiciels sont produits sans que l'on vérifie la correction des fonctions. Souvent, les contraintes commerciales obligent à aller vite, d'où la présence de nombreuses failles.
Néanmoins, il est possible de faire ce travail et on le fait dans les cas où la sécurité est essentielle.
Attention cependant, vous pouvez écrire un programme Python exempt de failles, cela n'empêchera pas que Python a lui-même des failles qui pourront être exploitées ! Par exemple, certaines failles de sécurité exploiteront des défauts de gestion de la mémoire, ces défauts existant dans le langage de programmation lui-même.
===== Performances =====
Le temps d'exécution de la fonction dépend essentiellement du nombre de répétition de la boucle TANT QUE.
* Si le tableau contient 16 éléments. Combien de fois se répète la boucle ?
* Est ce que l'on peut avoir de la chance et avoir une fin plus rapide ?
* Et si le tableau compte 32 éléments ? 64 ? 128 ?
* En général, comment évolue le nombre d'exécution de la boucle quand ''n'' est multiplié par 2 ?