ALGORITHME DE RECHERCHE DICHOTOMIQUE

cosmobob Messages postés 700 Date d'inscription mardi 30 décembre 2003 Statut Membre Dernière intervention 27 janvier 2009 - 27 juil. 2005 à 10:17
mslider Messages postés 109 Date d'inscription jeudi 21 octobre 2004 Statut Membre Dernière intervention 7 mars 2010 - 31 mars 2009 à 22:09
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/32909-algorithme-de-recherche-dichotomique

mslider Messages postés 109 Date d'inscription jeudi 21 octobre 2004 Statut Membre Dernière intervention 7 mars 2010
31 mars 2009 à 22:09
bien moi j'ai essayé d'utiliser une méthode de recherche dichotomique sur mon problème(celui qui suit) et je me suis cassé les dents(pas toute) apparemment la dichotomie çà marche que pour la recherche de valeurs distinctes dans une liste et pas pour comparer des intervalles.
Bon, soit voilà le problémo:


je cherche à faire correspondre des intervalles entre eux, je m'explique:

- soit dans un premier fichier texte, disons file1.txt une suite d'intervalles de la forme:

id1 3455 3463
id2 3535 3544
id3 3601 3608
id4 3622 3630
id5 3631 3913
id6 3631 3759
id7 3631 5899
id8 3760 3913
id9 3760 5630
id10 3996 4276
id11 4486 4605
id12 4706 5095
id13 5174 5326
.../...

- dans un second fichier texte, disons file2.txt une aure suite d'intervalles de la forme:

acc_2419732 3268 3285
acc_3041065 3565 3583
acc_362358 3640 3656
acc_3279485 3793 3813
acc_3091017 3794 3811
acc_2807380 3832 3848
acc_3105138 3832 3848
acc_3105139 3832 3848
acc_3105140 3832 3848
acc_3116450 3832 3848
acc_86708 3832 3848
acc_1987802 3922 3938
acc_1679660 4113 4129
acc_891489 4113 4129
acc_2829973 4299 4318
acc_298381 4603 4619
.../...

la question est la suivante: quels sont les intervalles de mon fichier 2 (file2.txt) qui se retrouvent inclus parmi ceux du fichier 1 (file1.txt) ?
en écrivant un simple script en awk (pour les vieux pervers comme moi c sympa le awk):

#!/usr/bin/awk -f
#usage: myprog.awk file2.txt

BEGIN {
while((getline < "file1.txt") > 0){
cpt++
descr[cpt]=$1
start[cpt]=$2
end[cpt]=$3
}
close("file1.txt")
}
{
j=1
while(start[j]<=$2 && j<=cpt){
if(end[j]>=$3){print $1,$2,$3,descr[j],start[j],end[j];j++}
else{j++}
}
}

on obtient comme résultat:

acc_362358 3640 3656 id5 3631 3913
acc_362358 3640 3656 id6 3631 3759
acc_362358 3640 3656 id7 3631 5899
acc_3279485 3793 3813 id5 3631 3913
acc_3279485 3793 3813 id7 3631 5899
acc_3279485 3793 3813 id8 3760 3913
acc_3279485 3793 3813 id9 3760 5630
acc_3091017 3794 3811 id5 3631 3913
acc_3091017 3794 3811 id7 3631 5899
acc_3091017 3794 3811 id8 3760 3913
acc_3091017 3794 3811 id9 3760 5630
acc_2807380 3832 3848 id5 3631 3913
acc_2807380 3832 3848 id7 3631 5899
acc_2807380 3832 3848 id8 3760 3913
acc_2807380 3832 3848 id9 3760 5630
acc_3105138 3832 3848 id5 3631 3913
acc_3105138 3832 3848 id7 3631 5899
acc_3105138 3832 3848 id8 3760 3913
acc_3105138 3832 3848 id9 3760 5630
acc_3105139 3832 3848 id5 3631 3913
acc_3105139 3832 3848 id7 3631 5899
acc_3105139 3832 3848 id8 3760 3913
acc_3105139 3832 3848 id9 3760 5630
acc_3105140 3832 3848 id5 3631 3913
acc_3105140 3832 3848 id7 3631 5899
acc_3105140 3832 3848 id8 3760 3913
acc_3105140 3832 3848 id9 3760 5630
acc_3116450 3832 3848 id5 3631 3913
acc_3116450 3832 3848 id7 3631 5899
acc_3116450 3832 3848 id8 3760 3913
acc_3116450 3832 3848 id9 3760 5630
acc_86708 3832 3848 id5 3631 3913
acc_86708 3832 3848 id7 3631 5899
acc_86708 3832 3848 id8 3760 3913
acc_86708 3832 3848 id9 3760 5630
acc_1987802 3922 3938 id7 3631 5899
acc_1987802 3922 3938 id9 3760 5630
acc_1679660 4113 4129 id7 3631 5899
acc_1679660 4113 4129 id9 3760 5630
acc_1679660 4113 4129 id10 3996 4276
acc_891489 4113 4129 id7 3631 5899
acc_891489 4113 4129 id9 3760 5630à
acc_891489 4113 4129 id10 3996 4276
acc_2829973 4299 4318 id7 3631 5899
acc_2829973 4299 4318 id9 3760 5630
acc_298381 4603 4619 id7 3631 5899.
acc_298381 4603 4619 id9 3760 5630

voili, voilo, bon courage à tous ceux qui n'ont pas encore de dentiers
zoneg Messages postés 4 Date d'inscription vendredi 25 juillet 2003 Statut Membre Dernière intervention 21 décembre 2007
26 sept. 2005 à 18:58
Deck_bsd, tu peux au moins dire merci à Mathy (prof d'algorithmique qui a donné cette exercice début 2005)...

(Pour ceux qui n'aurait pas compris, on est dans le même établissement scolaire...)

A+ Deck ;)
cs_LiBe444 Messages postés 220 Date d'inscription dimanche 7 septembre 2003 Statut Membre Dernière intervention 7 avril 2007
10 août 2005 à 23:53
Justement, Deck_Bsd l'a écrite, c'est la fonction de prototype int rechDich (int D_intt[], int D_intvaleurRecherchee, int D_intborneInf, int D_intborneSup) ;
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
7 août 2005 à 15:00
Mais à part des paroles, on pourrait avoir la fonction en C qui fait ce que tu dis ???
cs_LiBe444 Messages postés 220 Date d'inscription dimanche 7 septembre 2003 Statut Membre Dernière intervention 7 avril 2007
7 août 2005 à 14:41
RD n'est rien de plus qu'une recherche dicothomique sur le modèle proposé par DECK_BSD, mais dans une écriture plus formelle.
cs_LiBe444 Messages postés 220 Date d'inscription dimanche 7 septembre 2003 Statut Membre Dernière intervention 7 avril 2007
7 août 2005 à 14:38
C'est normal que vous doutiez de mes propos en les jugeant peu crédibles car je ne suis pas un professeur mais on vous enseignera tout ça aussi...

le "2" en résultat représentait bien sûr l'indice où se trouve le un cherché.
L'exemple que je vous ai montré est ce qu'il y a de plus simple.
deck_bsd Messages postés 1243 Date d'inscription jeudi 31 mars 2005 Statut Membre Dernière intervention 3 août 2016 2
5 août 2005 à 19:39
oui attendons.
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
2 août 2005 à 17:47
Attendons au moins ses explications
deck_bsd Messages postés 1243 Date d'inscription jeudi 31 mars 2005 Statut Membre Dernière intervention 3 août 2016 2
2 août 2005 à 08:59
Lol oui mais sont programme lui il n'en à pas ptdr. Ckler aucun moyen de savoir de quelle coté il est le 2.


++All
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
2 août 2005 à 08:37
Bien sur, je le vois avec mes yeux, on dirait que c'est comme ca que LiBe444 fait lui aussi
cosmobob Messages postés 700 Date d'inscription mardi 30 décembre 2003 Statut Membre Dernière intervention 27 janvier 2009 4
2 août 2005 à 00:52
comment voir que 2 est a gauche ou a droite ?
tu peux pas le deduire de la valeur des extrémités de ton sous tableau si le tableau est pas ordonné
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
1 août 2005 à 19:28
Il doit y a voir une recherche sous jacente qu'il ne prend pas en compte pour que le problème soit dichotomique. Par exemple, je recherche 2 dans le tableau non trié
[1,2,5,4,3,7,6,8]=[1, 2, 5, 4] [3, 7, 6, 8]
Je vois que 2 est dans la partie gauche donc je prend celle ci
[1, 2, 5, 4] = [1, 2], [5, 4] idem
[1, 2] = [1], [2] je vois que 2 est à droite
cosmobob Messages postés 700 Date d'inscription mardi 30 décembre 2003 Statut Membre Dernière intervention 27 janvier 2009 4
1 août 2005 à 11:42
je pense qu'il a du mal a piger lui meme ce qu'il raconte ...
ca n'explique pas pourquoi tu t'orientes vers la sous partie gauche du tableau plutot que vers la droite ce que tu racontes...
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
29 juil. 2005 à 19:52
Soit tu expliques très mal, soit c'est moi qui comprends rien.
cs_LiBe444 Messages postés 220 Date d'inscription dimanche 7 septembre 2003 Statut Membre Dernière intervention 7 avril 2007
29 juil. 2005 à 19:27
Essayons :
RD(#(2,1,2,3,2,3,4,5),1,plancher(1+8/2)) RD(#(2,1,2,3),1,plancher(1+4/2)) 2

où #() est un tableau en Scheme.

Essayez le avec mon interpreteur de langage "K" (c'est mon script que personne ne regarde)
cosmobob Messages postés 700 Date d'inscription mardi 30 décembre 2003 Statut Membre Dernière intervention 27 janvier 2009 4
28 juil. 2005 à 16:07
ouais comment tu trouves 1 par dichotomie dans le tableau 2 1 2 3 2 3 4 5 ?
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
28 juil. 2005 à 15:16
Je crois que les professeurs sont en vacances actuellement, tu peux donc nnous montrer ici comme tu fais ca avec dichotomie (j'ai pas trop compris ton explication)
Pour le coup du surjectif, tu parle de l'application x->T[x]? Celle la a l'air plutot injective non? j'ai un peu oublié tout ca...
cs_LiBe444 Messages postés 220 Date d'inscription dimanche 7 septembre 2003 Statut Membre Dernière intervention 7 avril 2007
27 juil. 2005 à 20:23
euh zut T[inf]<=x et T[sup]>=x ou alors T[inf]>=x et T[sup]<=x
cs_LiBe444 Messages postés 220 Date d'inscription dimanche 7 septembre 2003 Statut Membre Dernière intervention 7 avril 2007
27 juil. 2005 à 20:21
Vecchio la réponse est oui justement (je l'ai étudié en plus). Fais toi un petit exemple.

Quand on varie de un ou de zéro en croissant ou en décroissant, prendre un plus petit intervalle implique que la valeur se trouve dedans. Or nécessairement elle y est puisque on a par hypothèse soit que la valeur n'y est pas (et dans ce cas pas dans le tableau tout entier) soit elle y est au moins une fois car T[inf]<x et T[sup]>x ou alors T[inf]<x et T[sup]>x. Comme les valeurs de T sont "surjectives" (pour vous l'imager bien que T ne soit pas une fonction), x figure obligatoirement dans le sous ensemble. Donc la recherche dicothomique marche.
Un doute ? Demandez le à votre professeur d'informatique (même s'il est à la plage ça peut bouillonner)
deck_bsd Messages postés 1243 Date d'inscription jeudi 31 mars 2005 Statut Membre Dernière intervention 3 août 2016 2
27 juil. 2005 à 16:07
vecchio -> oui moi aussi je la trouve compréhensible je l'ai d'ailleur mis ds un de mais post en réponse a brunews. Pour ce qui est du problème , oui tu a raison lol, mais bon c lui ki la posser donc c'est pas a nous de mettre un piège ;)
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
27 juil. 2005 à 15:37
LiBe444 j'ai pas trop compris ton problème... ya même pas de piège, la réponse est évidemment non
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
27 juil. 2005 à 15:33
Moi je trouve que la version itérative est très compréhensible si on choisit bien ses noms de variables:

/* dicho: cherche x dans v[0..n], avec (0 <= i < j < n) => v[i] < v[j]
int dicho(int x, int v[], int n)
{
int droite n - 1, gauche 0;
while(gauche <= droite)
{
int milieu = (gauche + droite) / 2;
if(x < v[milieu]) droite = milieu - 1;
else if(x > v[milieu]) gauche = milieu + 1;
else return milieu;
}
return -1;
}
deck_bsd Messages postés 1243 Date d'inscription jeudi 31 mars 2005 Statut Membre Dernière intervention 3 août 2016 2
27 juil. 2005 à 14:44
Mais avec cette suite la rech dico ne saurai pas fonctionnée ou partiellement
deck_bsd Messages postés 1243 Date d'inscription jeudi 31 mars 2005 Statut Membre Dernière intervention 3 août 2016 2
27 juil. 2005 à 14:36
A c'est bien vu ça :s .
cs_LiBe444 Messages postés 220 Date d'inscription dimanche 7 septembre 2003 Statut Membre Dernière intervention 7 avril 2007
27 juil. 2005 à 14:30
N'oublie pas la valeur absolue dans l'inegalité |T[i+1]-T[i]|<=1
Cela signifie que le tableau varie d'amplitude maximale un de proche en proche ; exemple :

la suite 8 7 7 6 5 4 5 6 7 8 9 9 8 7 6 5 4 3

Aucun ordre total ne régit deux éléments isolés.
deck_bsd Messages postés 1243 Date d'inscription jeudi 31 mars 2005 Statut Membre Dernière intervention 3 août 2016 2
27 juil. 2005 à 14:20
Looooooooool on va bientot faire un cours ici mdr
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
27 juil. 2005 à 13:49
Révisons les classiques, rien de tel que Robert Sedgewick:

int __stdcall RechDicho(const int *parray, int nelem, int val)
{
int pos, n, i;
if((n = nelem) <= 0) goto notFOUND;
if(val == parray[0]) return 0;
pos = 1;
while(n >= pos) {
i = (pos + n) / 2;
if(val < parray[i]) n = i - 1;
else pos = i + 1;
if(val == parray[i]) return i;
}
notFOUND: return -1;
}
deck_bsd Messages postés 1243 Date d'inscription jeudi 31 mars 2005 Statut Membre Dernière intervention 3 août 2016 2
27 juil. 2005 à 13:48
ou un nombre négatif exemple -3 -(-5) = 2
deck_bsd Messages postés 1243 Date d'inscription jeudi 31 mars 2005 Statut Membre Dernière intervention 3 août 2016 2
27 juil. 2005 à 13:45
a première vue pour ton problem n°2 je dirai oui car vu que c'est un tableau d'élément trier, le chiffre après est tjrs supérieur ou égale a au précédent donc si on le soustrait le 2ième du prémié on tombe forcément en négatif ou = a 1, sauf si l'entier est 0. Mais je v y réfléchir plus longuement. Je sais que tu fait ca pour comment dirai je me faire souffrire lol mais c'est quand mm cool.
deck_bsd Messages postés 1243 Date d'inscription jeudi 31 mars 2005 Statut Membre Dernière intervention 3 août 2016 2
27 juil. 2005 à 13:42
Raaaa, co oublié un truc . Dans mon explication du problem 1 (lol on va y arriver ptdr) quand je dit que si le test est négatif on arrete, je veu préciser que l'on arret que si le test est négatif ou si on a trouvé l'élément recherché.
deck_bsd Messages postés 1243 Date d'inscription jeudi 31 mars 2005 Statut Membre Dernière intervention 3 août 2016 2
27 juil. 2005 à 13:37
Libe444 , Pour ton 1er problème ma réponse, sur le test d'une valeur supérieur etait évidement incorporer ds la recherche dicotomique, je voulai juste dire, que on test comme dans l'algo que g mis si le tableau n'est pas vide, si c'est le cas, on effectue une 1er fois la recherche , une fois cette recherche effectuée on fait alors le test que j'ai décrit plus haut, si le test est positif on continue la recherche dico, si il est négatif, c'est qu'il n'y a plus de valeur et donc la recherche s'arrèt et l'on renvoie le résultat.
Pour ce qui est dut 2ième, je doit avouer que ca me parait bizar, je doit prouver en faite que pour tout i, si on fait la valeur pointée par l'indice i + 1 - cette mm valeur on doit aboutir a une résultat plus petit ou égale a 1?
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
27 juil. 2005 à 12:55
OUPS, exact ça manque de dichotomie.
J'y ai repensé après avoir posté, je revois la question dès que possible.
cs_LiBe444 Messages postés 220 Date d'inscription dimanche 7 septembre 2003 Statut Membre Dernière intervention 7 avril 2007
27 juil. 2005 à 12:37
Tiens un problème de partiel tant qu'on y est.
Est ce que la recherche dicothomique marche sur un tableau tel que pour tout i, |T[i+1]-T[i]|<=1 ?
Essaie et conclue avec un exemple.
S'il est vrai que tu ne t'es jamais posé de telles questions, reflechir dessus te fera prendre de l'avance si tu veux faire de l'informatique ton metier.
cs_LiBe444 Messages postés 220 Date d'inscription dimanche 7 septembre 2003 Statut Membre Dernière intervention 7 avril 2007
27 juil. 2005 à 12:27
- D'accord. Ca se tient comme argument.
- La solution que tu m'a proposé ensuite est un parcours sequentiel donc ce n'est pas de la dicotomie.
L'idée est de tester si T[n] est inferieur ou superieur à la valeur cherchée. En fonction de ce test, soit on effectue une recherche dicotomique entre n/2 et n (car T[n/2]<x et T[n]>x), soit on multiplie n par deux.
deck_bsd Messages postés 1243 Date d'inscription jeudi 31 mars 2005 Statut Membre Dernière intervention 3 août 2016 2
27 juil. 2005 à 11:49
Merci BruNews pour l'exemple itératif, mais je l'avai déjà fait :D, oui car c'était un exercice de labo algo et nous avions du faire les deux. Mais j'ai réfèrée mettre le récursif, car il est plus facile a la compréhension.
Comme le dit mon profs de concept, il est parfois préfèrable de ne pas optimiser au maximum un code , car il se pourrai que après celui-ci ne sois plus très compréhensible. Donc je préfères 100fois utilisé un peu plus de mémoire et que mon code soit compréhensible que de tout rétressir lol, surtout que maintenant la mémoire n'est plus une denrée rare comme dans le temps. Mais c'est vrai qu'il faut optimiser sont code, mais pas jusqu'a le rendre incompréhensible. Mais tu a raison que pour la recherche dico on aurai pus prendre l'itératif.

PS: j'ai mis cette source dans initié car, un débutant ds la programmation en générale ne sais pas ce qu'est un algorithme ou alors en à une idée très vague.

++All
deck_bsd Messages postés 1243 Date d'inscription jeudi 31 mars 2005 Statut Membre Dernière intervention 3 août 2016 2
27 juil. 2005 à 11:42
Je ne voi pas ou est le problem, il suffit de tester si il y à une valeur après chaque recherche après l'indice de la valeur trouvée, si il n'y en a pas, on arrete la recherche et selon que l'on aie trouver le résultat ou non, on renvoie la valeur apropriée, voila g méditer satisfait?. (Je sais , ce n'est pas très clair comme explication lol)
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
27 juil. 2005 à 11:35
allez c'est pas dramatique le niveau de la source.

Lui fournir un exemple itératif sera plus profitable (enlevez les goto s'ils vous font mal aux yeux):

int __stdcall RechDicho(const int *parray, int nelem, int val)
{
int i, n; // i = PIVOT CENTRAL
if(nelem <= 0) goto notFOUND;
i = nelem / 2;
if(parray[i] == val) goto okFOUND;
if(parray[i] < val) {
while(++i < nelem) {
n = parray[i];
if(n == val) goto okFOUND;
if(n > val) break; // ON SORT ILLICO
}
}
else {
while(--i >= 0) {
n = parray[i];
if(n == val) goto okFOUND;
if(n < val) break; // ON SORT ILLICO
}
}
notFOUND: return -1;
okFOUND: return i;
}
cs_LiBe444 Messages postés 220 Date d'inscription dimanche 7 septembre 2003 Statut Membre Dernière intervention 7 avril 2007
27 juil. 2005 à 10:57
Je regrette d'avoir mis ma source en très débutant s'il faut être initié pour connaître la recherche dichotomique...

Penche toi plutôt sur cet exemple : comment trouver une valeur dans un tableau trié de longueur inconnue (sans chercher à la connaître) ?
On part du predicat que l'on ne cherche pas le maximum.
(c'est aussi de la dicotomie)
A méditer...
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
27 juil. 2005 à 10:37
Clair que pour une recherche dichotomique faut que le tableau soit trié.

Quel besoin de la récursivité ??? On fait idem en itératif et c'est nettement plus rapide, on supprime en plus un param en ne donnant que le nbr d'élements du tableau.
deck_bsd Messages postés 1243 Date d'inscription jeudi 31 mars 2005 Statut Membre Dernière intervention 3 août 2016 2
27 juil. 2005 à 10:28
Bien joué, j'ai oublié de le mensionner.

Merci pour le rapelle.
cosmobob Messages postés 700 Date d'inscription mardi 30 décembre 2003 Statut Membre Dernière intervention 27 janvier 2009 4
27 juil. 2005 à 10:17
salut,
t'as oublié de dire qu'il fallait que ton tableau soit trié pour que ca marche bien, ce qui est une condition très forte.

a+
Rejoignez-nous