Exercices d'entraînement☘
Ces exercices doivent être utilisés pour vous entraîner à programmer. Ils sont généralement accompagnés d'aide et de leur solution pour vous permettre de progresser.
Avant de vous précipiter sur ces solutions dès la première difficulté, n'oubliez pas les conseils suivants :
- Avez-vous bien fait un schéma au brouillon pour visualiser le problème posé ?
- Avez-vous essayé de rédiger un algorithme en français, avec vos propres mots, avant de vous lancer dans la programmation sur machine ?
- Avez-vous utilisé des affichages intermédiaires, des
print()
, pour visualiser au fur et à mesure le contenu des variables ? - Avez-vous testé le programme avec les propositions de tests donnés dans l'exercice ?
- Avez-vous testé le programme avec de nouveaux tests, différents de ceux proposés ?
Rappels
- Chaque programme Python doit être sauvegardé sous forme de fichier texte
avec l'extension
.py
.
Enregistrez ce fichier dans le dossier[E05-Recherche_Textuelle]
avec le nom donné à l'exercice :ProgE05.51.py
,ProgE05.52.py
, etc... - Pour exécuter ce programme, il suffit de le sauvegarder puis d'appuyer
sur la touche
[F5]
. - Le programme principal doit contenir un appel au module
doctest
:##----- Programme principal et tests -----## if __name__ == '__main__': import doctest doctest.testmod()
ProgE05.51 - Tableau de dictionnaires des mauvais caractères☘
Dans cet exercice, on choisit d'optimiser le calcul du décalage en construisant
un tableau de taille p
(longueur du motif) contenant les p
dictionnaires
respectifs des mauvais caractères de la chaîne motif[0..j]
. Chaque dictionnaire
associe à chaque caractère de motif[0..j]
son indice « le plus à droite »
(dernier indice de la chaîne exclus).
-
Copiez, collez et complétez la définition de la fonction
bad_carac_tab_horspool()
qui prend en paramètre une chaîne de caractèremotif
et qui renvoie un tableau des mauvais caractères demotif[0..j]
pour chaque indicej
, avec0
≤j
<len(motif)
, obtenus selon le principe énoncé plus haut.Rappel
motif[0..j]
est la chaîne constituée des caractères demotif
de l'indice0
(inclus) à l'indicej
(exclus).1 2 3 4 5 6 7 8 9 10 11
def bad_carac_tab_horspool(motif): """ motif - str, chaîne de caractères Sortie: list - tableau des dictionnaires tel que, pour chaque indice j : - les clefs sont les caractères de motif[0..j] - les valeurs associées sont leur indice "le plus à droite" dans motif[0..j] >>> motif = 'CAAGT' >>> bad_carac_tab_horspool(motif) [{}, {'C': 0}, {'C': 0, 'A': 1}, {'C': 0, 'A': 2}, {'C': 0, 'A': 2, 'G': 3}] """
Exemples de tests
>>> bad_carac_tab_horspool('witch') [{}, {'w': 0}, {'w': 0, 'i': 1}, {'w': 0, 'i': 1, 't': 2}, {'w': 0, 'i': 1, 't': 2, 'c': 3}] >>> bad_carac_tab_horspool('Horspool') [{}, {'H': 0}, {'H': 0, 'o': 1}, {'H': 0, 'o': 1, 'r': 2}, {'H': 0, 'o': 1, 'r': 2, 's': 3}, {'H': 0, 'o': 1, 'r': 2, 's': 3, 'p': 4}, {'H': 0, 'o': 5, 'r': 2, 's': 3, 'p': 4}, {'H': 0, 'o': 6, 'r': 2, 's': 3, 'p': 4}] >>> bad_carac_tab_horspool('Boyer-Moore') [{}, {'B': 0}, {'B': 0, 'o': 1}, {'B': 0, 'o': 1, 'y': 2}, {'B': 0, 'o': 1, 'y': 2, 'e': 3}, {'B': 0, 'o': 1, 'y': 2, 'e': 3, 'r': 4}, {'B': 0, 'o': 1, 'y': 2, 'e': 3, 'r': 4, '-': 5}, {'B': 0, 'o': 1, 'y': 2, 'e': 3, 'r': 4, '-': 5, 'M': 6}, {'B': 0, 'o': 7, 'y': 2, 'e': 3, 'r': 4, '-': 5, 'M': 6}, {'B': 0, 'o': 8, 'y': 2, 'e': 3, 'r': 4, '-': 5, 'M': 6}, {'B': 0, 'o': 8, 'y': 2, 'e': 3, 'r': 9, '-': 5, 'M': 6}]
Une solution
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
def bad_carac_tab_horspool(motif): """ motif - str, chaîne de caractères Sortie: list - tableau des dictionnaires tel que, pour chaque indice j : - les clefs sont les caractères de motif[0..j] - les valeurs associées sont leur indice "le plus à droite" dans motif[0..j] >>> motif = 'CAAGT' >>> bad_carac_tab_horspool(motif) [{}, {'C': 0}, {'C': 0, 'A': 1}, {'C': 0, 'A': 2}, {'C': 0, 'A': 2, 'G': 3}] """ tab = [] for j in range(len(motif)): dico = {} for i in range(j): dico[motif[i]] = i tab.append(dico) return tab
-
Justifiez qu'il n'est pas nécessaire de réaliser un dictionnaire des mauvais caractères pour le dernier caractère du motif si celui-ci n'est pas présent à un autre endroit du motif.
Une solution
Soit
k
l'indice du dernier caractère du motif.-
Ou bien le caractère
texte[i+k]
correspond au dernier caractère du motif et il est inutile de faire appel au dictionnaire des mauvais caractères ; -
Ou bien
texte[i+k]
ne correspond pas au dernier caractère.
Alors on va chercher dans le dictionnaire des mauvais caractères la valeur associée à un autre caractère quemotif[k]
.
Dans les deux cas, il n'est pas utile de prendre en compte la position du caractère
motif[k]
dans le dictionnaire des mauvais caractères correspondant. -
-
Copiez, collez et complétez la définition de la fonction
nb_occurrences_tab_horspool()
qui prend en paramètres deux chaînes de caractèresmotif
ettexte
. Cette fonction renvoie le nombre d'occurrences de la chaînemotif
dans la chaînetexte
en utilisant le tableau de dictionnaires renvoyé par la fonctionbad_carac_tab_horspool()
définie dans la question 1.1 2 3 4 5 6 7 8 9 10 11 12
def nb_occurrences_tab_horspool(motif, texte): """ motif - str, chaîne de caractères texte - str, chaîne de caractères Sortie: int - Nombre d'occurrences de motif dans texte Recherche selon les principes de Horspool >>> motif = 'CAAGT' >>> texte = 'ATCAAGTTCAAGTCAGTCCCCAAGTTGATGCAAGT' >>> nb_occurrences_tab_horspool(motif, texte) 4 """
Exemples de tests
>>> motif1 = 'witch' >>> texte1 = 'A witch which switch' >>> nb_occurrences_tab_horspool(motif1, texte1) 2 >>> motif2 = 'CAACT' >>> texte2 = 'TACCTCCAACTAGTCAACTAGACT' >>> nb_occurrences_tab_horspool(motif2, texte2) 2
Une piste
Il ne faut pas hésiter à réutiliser la fonction
decalage_horspool()
définie dans le TP n°2.Une solution
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
def nb_occurrences_tab_horspool(motif, texte): """ motif - str, chaîne de caractères texte - str, chaîne de caractères Sortie: int - Nombre d'occurrences de motif dans texte Recherche selon les principes de Horspool >>> motif = 'CAAGT' >>> texte = 'ATCAAGTTCAAGTCAGTCCCCAAGTTGATGCAAGT' >>> nb_occurrences_tab_horspool(motif, texte) 4 """ p = len(motif) n = len(texte) tab_bad_carac = bad_carac_tab_horspool(motif) i = 0 compteur = 0 while i <= n-p: j = p-1 while j >= 0: if motif[j] != texte[i+j]: decalage = decalage_horspool(motif, texte, i, j, tab_bad_carac[j]) j = -2 else: j = j-1 # On a parcouru tout le motif : il est présent dans texte if j == -1: compteur += 1 decalage = p i += decalage return compteur
-
Le but de cette question est de vérifier si l'utilisation d'un tableau de dictionnaires des mauvais caractères optimise la recherche réalisé par la version « simplifiée » de Horspool.
-
Copiez, collez et complétez la définition de la fonction
nb_comparaisons_tab_horspool()
qui prend en paramètres deux chaînes de caractèresmotif
ettexte
. Cette fonction renvoie le nombre de comparaisons effectuées pour appliquer la recherche textuelle en utilisant le tableau de dictionnaires renvoyé par la fonctionbad_carac_tab_horspool()
.1 2 3 4 5 6 7 8 9 10 11 12 13
def nb_comparaisons_tab_horspool(motif, texte): """ motif - str, chaîne de caractères texte - str, chaîne de caractères Sortie: int - Nombre de comparaisons nécessaires pour déterminer les positions où trouver motif dans texte selon l'algorithme de recherche textuelle simplifié de Horspool >>> motif = 'CAAGT' >>> texte = 'ATCAAGTTCAAGTCAGTCCCCAAGTTGATGCAAGT' >>> nb_comparaisons_tab_horspool(motif, texte) 27 """
Exemples de tests
>>> motif1 = 'witch' >>> texte1 = 'A witch which switch' >>> nb_comparaisons_tab_horspool(motif1, texte1) 17 >>> motif2 = 'CAACT' >>> texte2 = 'TACCTCCAACTAGTCAACTAGACT' >>> nb_comparaisons_tab_horspool(motif2, texte2) 22
Une solution
Il est possible de recopier le code de la fonction
nb_occurrences_tab_horspool()
en insérant un compteur pour les comparaisons.La version proposée ci-dessous « expurge » le nombre d'occurrences et se concentre sur le nombre de comparaisons :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
def nb_comparaisons_tab_horspool(motif, texte): """ motif - str, chaîne de caractères texte - str, chaîne de caractères Sortie: int - Nombre de comparaisons nécessaires pour déterminer les positions où trouver motif dans texte selon l'algorithme de recherche textuelle simplifié de Horspool >>> motif = 'CAAGT' >>> texte = 'ATCAAGTTCAAGTCAGTCCCCAAGTTGATGCAAGT' >>> nb_comparaisons_tab_horspool(motif, texte) 27 """ p = len(motif) n = len(texte) tab_bad_carac = bad_carac_tab_horspool(motif) i = 0 nb_comparaisons = 0 while i <= n-p: j = p-1 while j >= 0: nb_comparaisons += 1 if motif[j] != texte[i+j]: decalage = decalage_horspool(motif, texte, i, j, tab_bad_carac[j]) j = -2 else: j = j-1 if j == -1: decalage = p i += decalage return nb_comparaisons
-
Comparez avec les résultats renvoyés par la fonction
nb_comparaisons_horspool()
définie dans le TP n°2.Une réponse
L'application de la fonction
nb_comparaisons_horspool()
sur les tests précédents ne semble pas optimiser grand chose :>>> motif1 = 'witch' >>> texte1 = 'A witch which switch' >>> nb_comparaisons_horspool(motif1, texte1) 17 >>> motif2 = 'CAACT' >>> texte2 = 'TACCTCCAACTAGTCAACTAGACT' >>> nb_comparaisons_horspool(motif2, texte2) 23
Il faut un test mieux choisi pour gagner en efficacité. Par exemple (gain de 20%) :
>>> motif3 = 'TAACT' >>> texte3 = 'TACCTCTAACTAGTTAACTAGACT' >>> nb_comparaisons_horspool(motif3, texte3) 25 >>> nb_comparaisons_tab_horspool(motif2, texte2) 21
-
ProgE05.52 - Mauvais caractères par Boyer-Moore☘
Dans cet exercice, on établit le dictionnaire des mauvais caractères à partir
de leur plus courte distance d
à la fin du motif, cette distance étant
strictement positive. Un caractère non présent dans le dictionnaire sera
associé à la longueur du motif.
Le décalage est alors le maximum entre 1
et d+j+1–p
, où p = len(motif)
.
Reprendre le déroulement du TP n°2 en mettant en place ce nouveau principe d'élaboration du dictionnaire des mauvais caractères. En d'autres termes :
-
Définir la fonction
bad_carac_boyer_moore()
qui prend en paramètre une chaîne de caractères (le motif) et qui renvoie un dictionnaire dont les clefs sont les différents caractères du motif associés à leur plus petite distance (strictement positive) au dernier caractère du motif.Exemples de tests
>>> bad_carac_boyer_moore('CAAGT') {'C': 4, 'A': 2, 'G': 1} >>> bad_carac_boyer_moore('witch') {'w': 4, 'i': 3, 't': 2, 'c': 1} >>> bad_carac_boyer_moore('Horspool') {'H': 7, 'o': 1, 'r': 5, 's': 4, 'p': 3} >>> bad_carac_boyer_moore('Boyer-Moore') {'B': 10, 'o': 2, 'y': 8, 'e': 7, 'r': 1, '-': 5, 'M': 4}
-
Définir la fonction
decalage_boyer_moore()
qui prend en paramètres deux chaînes de caractères (le motif et le texte), deux entiers strictement positifs (les indicesi
etj
) et un dictionnaire des mauvais caractères. Cette fonction renvoie le décalage entier à appliquer à la fenêtre en cas de non correspondance entretexte[i+j]
etmotif[j]
.Exemples de tests
>>> motif = 'CAAGT' >>> texte = 'ATCAAGTTCAAGTCAGTCCCCAAGTTGATGCAAGT' >>> bad_carac = {'C': 4, 'A': 2, 'G': 1} >>> decalage_boyer_moore(motif, texte, 5, 2, bad_carac) 3 >>> decalage_boyer_moore(motif, texte, 12, 4, bad_carac) 5
-
Définir la fonction
nb_occurrences_boyer_moore()
qui prend en paramètres deux chaînes de caractèresmotif
ettexte
. Cette fonction renvoie le nombre d'occurrences de la chaînemotif
dans la chaînetexte
en appliquant la règle des mauvais caractères de Boyer-Moore.Exemples de tests
>>> motif1 = 'witch' >>> texte1 = 'A witch which switch' >>> nb_occurrences_boyer_moore(motif1, texte1) 2 >>> motif2 = 'CAACT' >>> texte2 = 'TACCTCCAACTAGTCAACTAGACT' >>> nb_occurrences_boyer_moore(motif2, texte2) 2
-
Définir la fonction
nb_comparaisons_boyer_moore()
qui prend en paramètres deux chaînes de caractèresmotif
ettexte
.
Cette fonction renvoie le nombre de comparaisons effectuées pour déterminer (par exemple) les positions de la chaînemotif
dans la chaînetexte
en appliquant la règle des mauvais caractères de Boyer-Moore.Exemples de tests
>>> motif1 = 'witch' >>> texte1 = 'A witch which switch' >>> nb_comparaisons_boyer_moore(motif1, texte1) 17 >>> motif2 = 'CAACT' >>> texte2 = 'TACCTCCAACTAGTCAACTAGACT' >>> nb_comparaisons_boyer_moore(motif2, texte2) 27
-
Définir la fonction
affichage_boyer_moore()
qui prend en paramètres deux chaînes de caractèresmotif
ettexte
.
Cette fonction affiche dans la console la recherche des positions de la chaînemotif
dans la chaînetexte
en appliquant la règle des mauvais caractères de Boyer-Moore.Exemples de tests
>>> motif1 = 'witch' >>> texte1 = 'A witch which switch' >>> affichage_boyer_moore(motif1, texte1) A witch which switch witch witch witch witch witch witch witch >>> motif2 = 'CAACT' >>> texte2 = 'TACCTCCAACTAGTCAACTAGACT' >>> affichage_boyer_moore(motif2, texte2) TACCTCCAACTAGTCAACTAGACT CAACT CAACT CAACT CAACT CAACT CAACT CAACT CAACT CAACT CAACT CAACT CAACT CAACT
-
Que peut-on déduire de ce qui précède ?
Une réponse
Il semble qu'utiliser le critère des mauvais caractères de Horspool et celui des mauvais caractères de Boyer-Moore revienne au même.
Il reste à le prouver...
Solution - Le programme complet
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
|