Juste un avis perso : le retour de la fonction bsearch est peu exploitable.
Bien souvent, face à une liste croissante, on ne se préoccupe pas
essentiellement de savoir si un élément donné s'y trouve ou ne s'y
trouve pas, on cherche à savoir où il est placé dans la liste (et
éventuellement hors de la liste à gauche ou à droite). Or, quel que soit
l'algorithme utilisé par bsearch (recherche séquentielle ou
dichotomique), bsearch serait en mesure sans coût supplémentaire
excessif de donner cette position. Hélas bsearch se contente de donner
une réponse binaire. Et je trouve particulièrement agaçant d'avoir à me
recoder un truc aussi classique qu'une recherche dichotomique, pas vous ?
Primo, la recherche dichotomique dans un tableau en mémoire n'est pas une plaie à coder, tout au plus un rapide échauffement des petits doigts pour le petit déjeuner. Une implementation simple et de bon gout fait à peine un vingtaine de lignes:
void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) { size_t a = 0; size_t b = nmemb;
while (a < b) { size_t m = (a + b) / 2; const void *p = (const char *)base + m * size; int cmp = (*compar)(key, p); if (cmp < 0) b = m; else if (cmp > 0) a = m + 1; else return (void *)p; } return NULL; }
Il ne faut pas coder avant le petit dejeuner :-) La preuve, tu nous a fait une belle boucle infinie. (Et je ne vois pas l'utilite du +1 dans a = m +1).
On peut dans ce cas améliorer légèrement l'efficacité de la recherche et garantir de trouver le premier match en cas de doublons en remplacant les deux tests sur cmp par un seul (laissé au lecteur à titre d'exercice ;-).
Rien n'empeche de faire cela ici aussi, il suffit de tester l'egalite avant de retourner une valeur. C'est un gain meme si la valeur se trouve toujours dans le tableau.
Troisièmement, la recherche dichotomique n'est pas le meilleur algorithme pour le probleme posé (boggle solver). Il sera bien plus efficace de stocker tous les mots possibles dans un tableau associatif (hash table) convenablement dimensionné et avec une API de recherche efficace.
Il a l'air d'avoir besoin de prefixes (j'ai toujours pas ete voir le jeu), auquel cas une hash table n'est pas particulierement adaptee.
A+
-- Jean-Marc FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc Site de usenet-fr: http://www.usenet-fr.news.eu.org
"Charlie Gordon" <news@chqrlie.org> writes:
Primo, la recherche dichotomique dans un tableau en mémoire n'est pas une
plaie à coder, tout au plus un rapide échauffement des petits doigts pour
le petit déjeuner. Une implementation simple et de bon gout fait à peine
un vingtaine de lignes:
void *bsearch(const void *key, const void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *))
{
size_t a = 0;
size_t b = nmemb;
while (a < b) {
size_t m = (a + b) / 2;
const void *p = (const char *)base + m * size;
int cmp = (*compar)(key, p);
if (cmp < 0)
b = m;
else
if (cmp > 0)
a = m + 1;
else
return (void *)p;
}
return NULL;
}
Il ne faut pas coder avant le petit dejeuner :-) La preuve, tu nous a fait
une belle boucle infinie. (Et je ne vois pas l'utilite du +1 dans a = m
+1).
On peut dans ce cas améliorer légèrement l'efficacité de la recherche et
garantir de trouver le premier match en cas de doublons en remplacant les
deux tests sur cmp par un seul (laissé au lecteur à titre d'exercice ;-).
Rien n'empeche de faire cela ici aussi, il suffit de tester l'egalite avant
de retourner une valeur. C'est un gain meme si la valeur se trouve
toujours dans le tableau.
Troisièmement, la recherche dichotomique n'est pas le meilleur algorithme
pour le probleme posé (boggle solver). Il sera bien plus efficace de
stocker tous les mots possibles dans un tableau associatif (hash table)
convenablement dimensionné et avec une API de recherche efficace.
Il a l'air d'avoir besoin de prefixes (j'ai toujours pas ete voir le jeu),
auquel cas une hash table n'est pas particulierement adaptee.
A+
--
Jean-Marc
FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Primo, la recherche dichotomique dans un tableau en mémoire n'est pas une plaie à coder, tout au plus un rapide échauffement des petits doigts pour le petit déjeuner. Une implementation simple et de bon gout fait à peine un vingtaine de lignes:
void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) { size_t a = 0; size_t b = nmemb;
while (a < b) { size_t m = (a + b) / 2; const void *p = (const char *)base + m * size; int cmp = (*compar)(key, p); if (cmp < 0) b = m; else if (cmp > 0) a = m + 1; else return (void *)p; } return NULL; }
Il ne faut pas coder avant le petit dejeuner :-) La preuve, tu nous a fait une belle boucle infinie. (Et je ne vois pas l'utilite du +1 dans a = m +1).
On peut dans ce cas améliorer légèrement l'efficacité de la recherche et garantir de trouver le premier match en cas de doublons en remplacant les deux tests sur cmp par un seul (laissé au lecteur à titre d'exercice ;-).
Rien n'empeche de faire cela ici aussi, il suffit de tester l'egalite avant de retourner une valeur. C'est un gain meme si la valeur se trouve toujours dans le tableau.
Troisièmement, la recherche dichotomique n'est pas le meilleur algorithme pour le probleme posé (boggle solver). Il sera bien plus efficace de stocker tous les mots possibles dans un tableau associatif (hash table) convenablement dimensionné et avec une API de recherche efficace.
Il a l'air d'avoir besoin de prefixes (j'ai toujours pas ete voir le jeu), auquel cas une hash table n'est pas particulierement adaptee.
A+
-- Jean-Marc FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc Site de usenet-fr: http://www.usenet-fr.news.eu.org
candide
Charlie Gordon a écrit :
P4) il faut se recoder une recherche dichotomique, quelle plaie !
Primo, la recherche dichotomique dans un tableau en mémoire n'est pas une plaie à coder, tout au plus un rapide échauffement des petits doigts pour le petit déjeuner. Une implementation simple et de bon gout fait à peine un vingtaine de lignes:
C'est une plaie tout simplement parce que c'est une plaie de réinventer la roue chaque matin au petit déjeuner ... Quant à la longueur, ce n'est pas un argument.
void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) { size_t a = 0; size_t b = nmemb;
while (a < b) { size_t m = (a + b) / 2; const void *p = (const char *)base + m * size; int cmp = (*compar)(key, p); if (cmp < 0) b = m; else if (cmp > 0) a = m + 1; else return (void *)p; } return NULL; }
Et ce genre de code, il faut pas mal d'années de pratique pour arriver à le pondre en 20 minutes et au saut du lit.
Secondo, la sémantique qui t'intéresse est triviale à obtenir en remplacant
C'est ce que je dis depuis le début mais je n'ai pas envie de recoder bsearch pour lui rajouter une trivialité.
Troisièmement, la recherche dichotomique n'est pas le meilleur algorithme pour le probleme posé (boggle solver). Il sera bien plus efficace de stocker tous les mots possibles dans un tableau associatif (hash table) convenablement dimensionné et avec une API de recherche efficace.
Oui, tu veux dire la structure (le /trie/) dont Jean-Marc a parlé ci-dessus. Décidément les informaticiens vous êtes faits sur le même moule, je parlais de ce problème avec un collègue informaticien et il m'a répondu exactement la même chose que vous.
À problème simple j'aime bien essayer d'apporter une solution simple. Il existe un algorithme de recherche de mot naïf et facile à implémenter qui simule complètement la structure de données évoquées par JMB (sauf que le parcours séquentiel des successeurs d'un noeud est remplacé par une recherche dichotomique).
Il est vrai néanmoins que cette structure de données est bien adaptée au problème posée et qu'elle diminuera la taille des données à consulter et que l'exécution sera sensiblement plus rapide. Mais le binary search est aussi assez rapide surtout si tu l'aides en lui donnant les adresses des lettres initiales (ce sont elles qui nécessitent le traitement le plus long). Moi j'ai l'impression que les temps sont assez comparables.
Ce qui ne m'incite pas à choisir la structure de données c'est qu'il faut s'en taper l'implémentation puis la routine de recherche dans le /trie/, conceptuellement assez facile, techniquement moins facile. Mais avec plus de pratique peut-être effectivement que je ferais comme vous.
Charlie Gordon a écrit :
P4) il faut se recoder une recherche dichotomique, quelle plaie !
Primo, la recherche dichotomique dans un tableau en mémoire n'est pas une
plaie à coder, tout au plus un rapide échauffement des petits doigts pour le
petit déjeuner. Une implementation simple et de bon gout fait à peine un
vingtaine de lignes:
C'est une plaie tout simplement parce que c'est une plaie de réinventer
la roue chaque matin au petit déjeuner ... Quant à la longueur, ce n'est
pas un argument.
void *bsearch(const void *key, const void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *))
{
size_t a = 0;
size_t b = nmemb;
while (a < b) {
size_t m = (a + b) / 2;
const void *p = (const char *)base + m * size;
int cmp = (*compar)(key, p);
if (cmp < 0)
b = m;
else
if (cmp > 0)
a = m + 1;
else
return (void *)p;
}
return NULL;
}
Et ce genre de code, il faut pas mal d'années de pratique pour arriver à
le pondre en 20 minutes et au saut du lit.
Secondo, la sémantique qui t'intéresse est triviale à obtenir en remplacant
C'est ce que je dis depuis le début mais je n'ai pas envie de recoder
bsearch pour lui rajouter une trivialité.
Troisièmement, la recherche dichotomique n'est pas le meilleur algorithme
pour le probleme posé (boggle solver). Il sera bien plus efficace de stocker
tous les mots possibles dans un tableau associatif (hash table)
convenablement dimensionné et avec une API de recherche efficace.
Oui, tu veux dire la structure (le /trie/) dont Jean-Marc a parlé
ci-dessus. Décidément les informaticiens vous êtes faits sur le même
moule, je parlais de ce problème avec un collègue informaticien et il
m'a répondu exactement la même chose que vous.
À problème simple j'aime bien essayer d'apporter une solution simple. Il
existe un algorithme de recherche de mot naïf et facile à implémenter
qui simule complètement la structure de données évoquées par JMB (sauf
que le parcours séquentiel des successeurs d'un noeud est remplacé par
une recherche dichotomique).
Il est vrai néanmoins que cette structure de données est bien adaptée au
problème posée et qu'elle diminuera la taille des données à consulter et
que l'exécution sera sensiblement plus rapide. Mais le binary search est
aussi assez rapide surtout si tu l'aides en lui donnant les adresses des
lettres initiales (ce sont elles qui nécessitent le traitement le plus
long). Moi j'ai l'impression que les temps sont assez comparables.
Ce qui ne m'incite pas à choisir la structure de données c'est qu'il
faut s'en taper l'implémentation puis la routine de recherche dans le
/trie/, conceptuellement assez facile, techniquement moins facile. Mais
avec plus de pratique peut-être effectivement que je ferais comme vous.
P4) il faut se recoder une recherche dichotomique, quelle plaie !
Primo, la recherche dichotomique dans un tableau en mémoire n'est pas une plaie à coder, tout au plus un rapide échauffement des petits doigts pour le petit déjeuner. Une implementation simple et de bon gout fait à peine un vingtaine de lignes:
C'est une plaie tout simplement parce que c'est une plaie de réinventer la roue chaque matin au petit déjeuner ... Quant à la longueur, ce n'est pas un argument.
void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) { size_t a = 0; size_t b = nmemb;
while (a < b) { size_t m = (a + b) / 2; const void *p = (const char *)base + m * size; int cmp = (*compar)(key, p); if (cmp < 0) b = m; else if (cmp > 0) a = m + 1; else return (void *)p; } return NULL; }
Et ce genre de code, il faut pas mal d'années de pratique pour arriver à le pondre en 20 minutes et au saut du lit.
Secondo, la sémantique qui t'intéresse est triviale à obtenir en remplacant
C'est ce que je dis depuis le début mais je n'ai pas envie de recoder bsearch pour lui rajouter une trivialité.
Troisièmement, la recherche dichotomique n'est pas le meilleur algorithme pour le probleme posé (boggle solver). Il sera bien plus efficace de stocker tous les mots possibles dans un tableau associatif (hash table) convenablement dimensionné et avec une API de recherche efficace.
Oui, tu veux dire la structure (le /trie/) dont Jean-Marc a parlé ci-dessus. Décidément les informaticiens vous êtes faits sur le même moule, je parlais de ce problème avec un collègue informaticien et il m'a répondu exactement la même chose que vous.
À problème simple j'aime bien essayer d'apporter une solution simple. Il existe un algorithme de recherche de mot naïf et facile à implémenter qui simule complètement la structure de données évoquées par JMB (sauf que le parcours séquentiel des successeurs d'un noeud est remplacé par une recherche dichotomique).
Il est vrai néanmoins que cette structure de données est bien adaptée au problème posée et qu'elle diminuera la taille des données à consulter et que l'exécution sera sensiblement plus rapide. Mais le binary search est aussi assez rapide surtout si tu l'aides en lui donnant les adresses des lettres initiales (ce sont elles qui nécessitent le traitement le plus long). Moi j'ai l'impression que les temps sont assez comparables.
Ce qui ne m'incite pas à choisir la structure de données c'est qu'il faut s'en taper l'implémentation puis la routine de recherche dans le /trie/, conceptuellement assez facile, techniquement moins facile. Mais avec plus de pratique peut-être effectivement que je ferais comme vous.
candide
Charlie Gordon a écrit :
J'ai peur que cette dernière remarque soit à prendre au premier degré... Faut-il que les étudiants soient bien intoxiqués de langages fonctionnels pour imaginer systématiquement des solutions recursives aux problèmes les plus simples ?
Je ne connais aucun langage fonctionnel. La récursivité ici est assez naturelle et le code est, je trouve, plus lisible. Et pour moi, la lisibilité, ça compte.
Pourquoi pour qsort on implémente récursif et on ne le ferait pas pour bsearch après tout ?
Charlie Gordon a écrit :
J'ai peur que cette dernière remarque soit à prendre au premier degré...
Faut-il que les étudiants soient bien intoxiqués de langages fonctionnels
pour imaginer systématiquement des solutions recursives aux problèmes les
plus simples ?
Je ne connais aucun langage fonctionnel. La récursivité ici est assez
naturelle et le code est, je trouve, plus lisible. Et pour moi, la
lisibilité, ça compte.
Pourquoi pour qsort on implémente récursif et on ne le ferait pas pour
bsearch après tout ?
J'ai peur que cette dernière remarque soit à prendre au premier degré... Faut-il que les étudiants soient bien intoxiqués de langages fonctionnels pour imaginer systématiquement des solutions recursives aux problèmes les plus simples ?
Je ne connais aucun langage fonctionnel. La récursivité ici est assez naturelle et le code est, je trouve, plus lisible. Et pour moi, la lisibilité, ça compte.
Pourquoi pour qsort on implémente récursif et on ne le ferait pas pour bsearch après tout ?
espie
In article <gc2i75$d3d$, Charlie Gordon wrote:
J'ai peur que cette dernière remarque soit à prendre au premier degré... Faut-il que les étudiants soient bien intoxiqués de langages fonctionnels pour imaginer systématiquement des solutions recursives aux problèmes les plus simples ?
Parce que, dans ce cas precis, c'est de la recursion terminale, et que donc tout compilateur decent saura faire de la tail-recursion optimization, et donc que c'est strictement equivalent a la solution iterative ?
In article <gc2i75$d3d$1@registered.motzarella.org>,
Charlie Gordon <news@chqrlie.org> wrote:
J'ai peur que cette dernière remarque soit à prendre au premier degré...
Faut-il que les étudiants soient bien intoxiqués de langages fonctionnels
pour imaginer systématiquement des solutions recursives aux problèmes les
plus simples ?
Parce que, dans ce cas precis, c'est de la recursion terminale, et que donc
tout compilateur decent saura faire de la tail-recursion optimization,
et donc que c'est strictement equivalent a la solution iterative ?
J'ai peur que cette dernière remarque soit à prendre au premier degré... Faut-il que les étudiants soient bien intoxiqués de langages fonctionnels pour imaginer systématiquement des solutions recursives aux problèmes les plus simples ?
Parce que, dans ce cas precis, c'est de la recursion terminale, et que donc tout compilateur decent saura faire de la tail-recursion optimization, et donc que c'est strictement equivalent a la solution iterative ?
candide
Jean-Marc Bourguet a écrit :
(...) tu nous a fait une belle boucle infinie.
Exemple ?
(Et je ne vois pas l'utilite du +1 dans a = m +1).
Quelque chose doit m'échapper car ça me parait clair pourtant : on ne va pas tester le cas a=m puisque cmp !=0 donc on commence au premier qui suit i.e. m+1.
Jean-Marc Bourguet a écrit :
(...) tu nous a fait
une belle boucle infinie.
Exemple ?
(Et je ne vois pas l'utilite du +1 dans a = m
+1).
Quelque chose doit m'échapper car ça me parait clair pourtant : on ne va
pas tester le cas a=m puisque cmp !=0 donc on commence au premier qui
suit i.e. m+1.
(Et je ne vois pas l'utilite du +1 dans a = m +1).
Quelque chose doit m'échapper car ça me parait clair pourtant : on ne va pas tester le cas a=m puisque cmp !=0 donc on commence au premier qui suit i.e. m+1.
-ed-
On 1 oct, 12:39, candide wrote:
Bonjour,
Juste un avis perso : le retour de la fonction bsearch est peu exploitabl e.
Bien souvent, face à une liste croissante, on ne se préoccupe pas essentiellement de savoir si un élément donné s'y trouve ou ne s'y trouve pas, on cherche à savoir où il est placé dans la liste (et éventuellement hors de la liste à gauche ou à droite). Or, quel que soit l'algorithme utilisé par bsearch (recherche séquentielle ou dichotomique), bsearch serait en mesure sans coût supplémentaire excessif de donner cette position. Hélas bsearch se contente de donn er une réponse binaire. Et je trouve particulièrement agaçant d'avoir à me recoder un truc aussi classique qu'une recherche dichotomique, pas vous ?
J'ai lu la suite et j'ai fini par comprendre ce que tu voulais. Non bsearch() sait pas faire. Il sait juste dire si un élément d'une liste triée est présent ou non. Pour faure ce que tu veux faire, il fait une interface un peu différente (à définir) et recoder une fonction de recherche génerique, ce qui n'est pas bien difficile.
Je rappelle que le C est un langage de base. Il fournit certains outils tous faits qui couvrent des cas simples. Par contre il fourni tout ce qui est nécessaire pour réaliser les cas compliqués.
On ne peut pas exiger d'un langage simple de bas niveau des fonctions complexes de haut niveau. Si c'est ce que tu cherches, le C++ est fait pour toi.
On 1 oct, 12:39, candide <cand...@free.invalid> wrote:
Bonjour,
Juste un avis perso : le retour de la fonction bsearch est peu exploitabl e.
Bien souvent, face à une liste croissante, on ne se préoccupe pas
essentiellement de savoir si un élément donné s'y trouve ou ne s'y
trouve pas, on cherche à savoir où il est placé dans la liste (et
éventuellement hors de la liste à gauche ou à droite). Or, quel que soit
l'algorithme utilisé par bsearch (recherche séquentielle ou
dichotomique), bsearch serait en mesure sans coût supplémentaire
excessif de donner cette position. Hélas bsearch se contente de donn er
une réponse binaire. Et je trouve particulièrement agaçant d'avoir à me
recoder un truc aussi classique qu'une recherche dichotomique, pas vous ?
J'ai lu la suite et j'ai fini par comprendre ce que tu voulais. Non
bsearch() sait pas faire. Il sait juste dire si un élément d'une liste
triée est présent ou non. Pour faure ce que tu veux faire, il fait une
interface un peu différente (à définir) et recoder une fonction de
recherche génerique, ce qui n'est pas bien difficile.
Je rappelle que le C est un langage de base. Il fournit certains
outils tous faits qui couvrent des cas simples. Par contre il fourni
tout ce qui est nécessaire pour réaliser les cas compliqués.
On ne peut pas exiger d'un langage simple de bas niveau des fonctions
complexes de haut niveau. Si c'est ce que tu cherches, le C++ est fait
pour toi.
Juste un avis perso : le retour de la fonction bsearch est peu exploitabl e.
Bien souvent, face à une liste croissante, on ne se préoccupe pas essentiellement de savoir si un élément donné s'y trouve ou ne s'y trouve pas, on cherche à savoir où il est placé dans la liste (et éventuellement hors de la liste à gauche ou à droite). Or, quel que soit l'algorithme utilisé par bsearch (recherche séquentielle ou dichotomique), bsearch serait en mesure sans coût supplémentaire excessif de donner cette position. Hélas bsearch se contente de donn er une réponse binaire. Et je trouve particulièrement agaçant d'avoir à me recoder un truc aussi classique qu'une recherche dichotomique, pas vous ?
J'ai lu la suite et j'ai fini par comprendre ce que tu voulais. Non bsearch() sait pas faire. Il sait juste dire si un élément d'une liste triée est présent ou non. Pour faure ce que tu veux faire, il fait une interface un peu différente (à définir) et recoder une fonction de recherche génerique, ce qui n'est pas bien difficile.
Je rappelle que le C est un langage de base. Il fournit certains outils tous faits qui couvrent des cas simples. Par contre il fourni tout ce qui est nécessaire pour réaliser les cas compliqués.
On ne peut pas exiger d'un langage simple de bas niveau des fonctions complexes de haut niveau. Si c'est ce que tu cherches, le C++ est fait pour toi.
Charlie Gordon
"Marc Espie" a écrit dans le message de news: gc2rma$20ac$
In article <gc2i75$d3d$, Charlie Gordon wrote:
J'ai peur que cette dernière remarque soit à prendre au premier degré... Faut-il que les étudiants soient bien intoxiqués de langages fonctionnels pour imaginer systématiquement des solutions recursives aux problèmes les plus simples ?
Parce que, dans ce cas precis, c'est de la recursion terminale, et que donc tout compilateur decent saura faire de la tail-recursion optimization, et donc que c'est strictement equivalent a la solution iterative ?
Cela ne m'a pas échappé : je l'avais même expliqué dans la partie du message que tu as coupée. Cependant je ne suis convaincu ni de l'élégance supérieure de la solution récursive, ni de la décence supposée des compilateurs courants.
-- Chqrlie.
"Marc Espie" <espie@lain.home> a écrit dans le message de news:
gc2rma$20ac$1@biggoron.nerim.net...
In article <gc2i75$d3d$1@registered.motzarella.org>,
Charlie Gordon <news@chqrlie.org> wrote:
J'ai peur que cette dernière remarque soit à prendre au premier degré...
Faut-il que les étudiants soient bien intoxiqués de langages fonctionnels
pour imaginer systématiquement des solutions recursives aux problèmes les
plus simples ?
Parce que, dans ce cas precis, c'est de la recursion terminale, et que
donc
tout compilateur decent saura faire de la tail-recursion optimization,
et donc que c'est strictement equivalent a la solution iterative ?
Cela ne m'a pas échappé : je l'avais même expliqué dans la partie du message
que tu as coupée.
Cependant je ne suis convaincu ni de l'élégance supérieure de la solution
récursive, ni de la décence supposée des compilateurs courants.
"Marc Espie" a écrit dans le message de news: gc2rma$20ac$
In article <gc2i75$d3d$, Charlie Gordon wrote:
J'ai peur que cette dernière remarque soit à prendre au premier degré... Faut-il que les étudiants soient bien intoxiqués de langages fonctionnels pour imaginer systématiquement des solutions recursives aux problèmes les plus simples ?
Parce que, dans ce cas precis, c'est de la recursion terminale, et que donc tout compilateur decent saura faire de la tail-recursion optimization, et donc que c'est strictement equivalent a la solution iterative ?
Cela ne m'a pas échappé : je l'avais même expliqué dans la partie du message que tu as coupée. Cependant je ne suis convaincu ni de l'élégance supérieure de la solution récursive, ni de la décence supposée des compilateurs courants.
-- Chqrlie.
Charlie Gordon
"candide" a écrit dans le message de news: 48e4df54$0$5901$
Charlie Gordon a écrit :
J'ai peur que cette dernière remarque soit à prendre au premier degré... Faut-il que les étudiants soient bien intoxiqués de langages fonctionnels pour imaginer systématiquement des solutions recursives aux problèmes les plus simples ?
Je ne connais aucun langage fonctionnel. La récursivité ici est assez naturelle et le code est, je trouve, plus lisible.
C'est un point de vue qui se défend.
Et pour moi, la lisibilité, ça compte.
Tout-à-fait d'accord ! La lisibilité est essentielle. Mais comme tu l'as remarqué dans une autre réponse, ma solution est assez claire.
Pourquoi pour qsort on implémente récursif et on ne le ferait pas pour bsearch après tout ?
Qsort est souvent implémenté avec une double récursion, qui n'est qu'en partie simplifiee par certains compilateurs. Faire une implementation non récursive n'est pas si facile. D'ailleurs il faut prendre des précautions subtiles pour éviter que dans des cas pathologiques la récursion ne se fasse trop violemment. En effet, avec un pivot mal choisi et une récursion systematique, on peut se retrouver à recurser sur une profondeur de l'ordre de la taille du tableau. La solution pour éviter cela est de ne recurser que sur la moitie la moins grande et de boucler explicitement sur l'autre. On n'évite pas nécessairement la complexité quadratique, mais on se garde d'exploser la pile. Voilà un cas concret ou le compilateur ne peut pas deviner quelle recursion terminale simplifier.
Je finirai sur une mise en garde : bsearch est considérablement plus simple que qsort. Il est encore facile de faire des erreurs d'implementation quand on code bsearch pour le petit dej, mais en ce qui concerne qsort, il est difficile de ne pas en faire. Ecrire un qsort sur une feuille blanche, qui fonctionne correctement du premier coup est une prouesse remarquable.
-- Chqrlie.
"candide" <candide@free.invalid> a écrit dans le message de news:
48e4df54$0$5901$426a74cc@news.free.fr...
Charlie Gordon a écrit :
J'ai peur que cette dernière remarque soit à prendre au premier degré...
Faut-il que les étudiants soient bien intoxiqués de langages fonctionnels
pour imaginer systématiquement des solutions recursives aux problèmes les
plus simples ?
Je ne connais aucun langage fonctionnel. La récursivité ici est assez
naturelle et le code est, je trouve, plus lisible.
C'est un point de vue qui se défend.
Et pour moi, la lisibilité, ça compte.
Tout-à-fait d'accord ! La lisibilité est essentielle. Mais comme tu l'as
remarqué dans une autre réponse, ma solution est assez claire.
Pourquoi pour qsort on implémente récursif et on ne le ferait pas pour
bsearch après tout ?
Qsort est souvent implémenté avec une double récursion, qui n'est qu'en
partie simplifiee par certains compilateurs. Faire une implementation non
récursive n'est pas si facile. D'ailleurs il faut prendre des précautions
subtiles pour éviter que dans des cas pathologiques la récursion ne se fasse
trop violemment. En effet, avec un pivot mal choisi et une récursion
systematique, on peut se retrouver à recurser sur une profondeur de l'ordre
de la taille du tableau. La solution pour éviter cela est de ne recurser
que sur la moitie la moins grande et de boucler explicitement sur l'autre.
On n'évite pas nécessairement la complexité quadratique, mais on se garde
d'exploser la pile. Voilà un cas concret ou le compilateur ne peut pas
deviner quelle recursion terminale simplifier.
Je finirai sur une mise en garde : bsearch est considérablement plus simple
que qsort. Il est encore facile de faire des erreurs d'implementation quand
on code bsearch pour le petit dej, mais en ce qui concerne qsort, il est
difficile de ne pas en faire. Ecrire un qsort sur une feuille blanche, qui
fonctionne correctement du premier coup est une prouesse remarquable.
"candide" a écrit dans le message de news: 48e4df54$0$5901$
Charlie Gordon a écrit :
J'ai peur que cette dernière remarque soit à prendre au premier degré... Faut-il que les étudiants soient bien intoxiqués de langages fonctionnels pour imaginer systématiquement des solutions recursives aux problèmes les plus simples ?
Je ne connais aucun langage fonctionnel. La récursivité ici est assez naturelle et le code est, je trouve, plus lisible.
C'est un point de vue qui se défend.
Et pour moi, la lisibilité, ça compte.
Tout-à-fait d'accord ! La lisibilité est essentielle. Mais comme tu l'as remarqué dans une autre réponse, ma solution est assez claire.
Pourquoi pour qsort on implémente récursif et on ne le ferait pas pour bsearch après tout ?
Qsort est souvent implémenté avec une double récursion, qui n'est qu'en partie simplifiee par certains compilateurs. Faire une implementation non récursive n'est pas si facile. D'ailleurs il faut prendre des précautions subtiles pour éviter que dans des cas pathologiques la récursion ne se fasse trop violemment. En effet, avec un pivot mal choisi et une récursion systematique, on peut se retrouver à recurser sur une profondeur de l'ordre de la taille du tableau. La solution pour éviter cela est de ne recurser que sur la moitie la moins grande et de boucler explicitement sur l'autre. On n'évite pas nécessairement la complexité quadratique, mais on se garde d'exploser la pile. Voilà un cas concret ou le compilateur ne peut pas deviner quelle recursion terminale simplifier.
Je finirai sur une mise en garde : bsearch est considérablement plus simple que qsort. Il est encore facile de faire des erreurs d'implementation quand on code bsearch pour le petit dej, mais en ce qui concerne qsort, il est difficile de ne pas en faire. Ecrire un qsort sur une feuille blanche, qui fonctionne correctement du premier coup est une prouesse remarquable.
-- Chqrlie.
Charlie Gordon
"Jean-Marc Bourguet" a écrit dans le message de news:
"Charlie Gordon" writes:
Primo, la recherche dichotomique dans un tableau en mémoire n'est pas une plaie à coder, tout au plus un rapide échauffement des petits doigts pour le petit déjeuner. Une implementation simple et de bon gout fait à peine un vingtaine de lignes:
void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) { size_t a = 0; size_t b = nmemb;
while (a < b) { size_t m = (a + b) / 2; const void *p = (const char *)base + m * size; int cmp = (*compar)(key, p); if (cmp < 0) b = m; else if (cmp > 0) a = m + 1; else return (void *)p; } return NULL; }
Il ne faut pas coder avant le petit dejeuner :-) La preuve, tu nous a fait une belle boucle infinie.
Ah bon ? Peux-tu être plus explicite ?
(Et je ne vois pas l'utilite du +1 dans a = m + 1).
Cela accélère la convergence : la clé est > au pivot donc l'element cherché est forcément strictement au delà du pivot.
On peut dans ce cas améliorer légèrement l'efficacité de la recherche et garantir de trouver le premier match en cas de doublons en remplacant les deux tests sur cmp par un seul (laissé au lecteur à titre d'exercice ;-).
Rien n'empeche de faire cela ici aussi, il suffit de tester l'egalite avant de retourner une valeur. C'est un gain meme si la valeur se trouve toujours dans le tableau.
Non, ce n'est pas loisible : dans le cas général on a plus de comparaisons avec *key != *p, donc il est préférable de tester ces cas en premier.
Troisièmement, la recherche dichotomique n'est pas le meilleur algorithme pour le probleme posé (boggle solver). Il sera bien plus efficace de stocker tous les mots possibles dans un tableau associatif (hash table) convenablement dimensionné et avec une API de recherche efficace.
Il a l'air d'avoir besoin de prefixes (j'ai toujours pas ete voir le jeu), auquel cas une hash table n'est pas particulierement adaptee.
Effectivement, si l'algorithme repose sur une recherche de prefixes, le hash est inadapté. Le probleme de Boggle a peut-etre une complexité supérieure au Scrabble, pour lequel un hash des combinaisons de lettres est a la base de programmes qui jouent des parties entières optimales en duplicate en une fraction de seconde.
-- Chqrlie.
"Jean-Marc Bourguet" <jm@bourguet.org> a écrit dans le message de news:
pxb3ajfm6h7.fsf@news.bourguet.org...
"Charlie Gordon" <news@chqrlie.org> writes:
Primo, la recherche dichotomique dans un tableau en mémoire n'est pas une
plaie à coder, tout au plus un rapide échauffement des petits doigts pour
le petit déjeuner. Une implementation simple et de bon gout fait à peine
un vingtaine de lignes:
void *bsearch(const void *key, const void *base, size_t nmemb, size_t
size,
int (*compar)(const void *, const void *))
{
size_t a = 0;
size_t b = nmemb;
while (a < b) {
size_t m = (a + b) / 2;
const void *p = (const char *)base + m * size;
int cmp = (*compar)(key, p);
if (cmp < 0)
b = m;
else
if (cmp > 0)
a = m + 1;
else
return (void *)p;
}
return NULL;
}
Il ne faut pas coder avant le petit dejeuner :-) La preuve, tu nous a fait
une belle boucle infinie.
Ah bon ? Peux-tu être plus explicite ?
(Et je ne vois pas l'utilite du +1 dans a = m + 1).
Cela accélère la convergence : la clé est > au pivot donc l'element cherché
est forcément strictement au delà du pivot.
On peut dans ce cas améliorer légèrement l'efficacité de la recherche et
garantir de trouver le premier match en cas de doublons en remplacant les
deux tests sur cmp par un seul (laissé au lecteur à titre d'exercice ;-).
Rien n'empeche de faire cela ici aussi, il suffit de tester l'egalite
avant
de retourner une valeur. C'est un gain meme si la valeur se trouve
toujours dans le tableau.
Non, ce n'est pas loisible : dans le cas général on a plus de comparaisons
avec *key != *p, donc il est préférable de tester ces cas en premier.
Troisièmement, la recherche dichotomique n'est pas le meilleur algorithme
pour le probleme posé (boggle solver). Il sera bien plus efficace de
stocker tous les mots possibles dans un tableau associatif (hash table)
convenablement dimensionné et avec une API de recherche efficace.
Il a l'air d'avoir besoin de prefixes (j'ai toujours pas ete voir le jeu),
auquel cas une hash table n'est pas particulierement adaptee.
Effectivement, si l'algorithme repose sur une recherche de prefixes, le hash
est inadapté.
Le probleme de Boggle a peut-etre une complexité supérieure au Scrabble,
pour lequel un hash des combinaisons de lettres est a la base de programmes
qui jouent des parties entières optimales en duplicate en une fraction de
seconde.
"Jean-Marc Bourguet" a écrit dans le message de news:
"Charlie Gordon" writes:
Primo, la recherche dichotomique dans un tableau en mémoire n'est pas une plaie à coder, tout au plus un rapide échauffement des petits doigts pour le petit déjeuner. Une implementation simple et de bon gout fait à peine un vingtaine de lignes:
void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) { size_t a = 0; size_t b = nmemb;
while (a < b) { size_t m = (a + b) / 2; const void *p = (const char *)base + m * size; int cmp = (*compar)(key, p); if (cmp < 0) b = m; else if (cmp > 0) a = m + 1; else return (void *)p; } return NULL; }
Il ne faut pas coder avant le petit dejeuner :-) La preuve, tu nous a fait une belle boucle infinie.
Ah bon ? Peux-tu être plus explicite ?
(Et je ne vois pas l'utilite du +1 dans a = m + 1).
Cela accélère la convergence : la clé est > au pivot donc l'element cherché est forcément strictement au delà du pivot.
On peut dans ce cas améliorer légèrement l'efficacité de la recherche et garantir de trouver le premier match en cas de doublons en remplacant les deux tests sur cmp par un seul (laissé au lecteur à titre d'exercice ;-).
Rien n'empeche de faire cela ici aussi, il suffit de tester l'egalite avant de retourner une valeur. C'est un gain meme si la valeur se trouve toujours dans le tableau.
Non, ce n'est pas loisible : dans le cas général on a plus de comparaisons avec *key != *p, donc il est préférable de tester ces cas en premier.
Troisièmement, la recherche dichotomique n'est pas le meilleur algorithme pour le probleme posé (boggle solver). Il sera bien plus efficace de stocker tous les mots possibles dans un tableau associatif (hash table) convenablement dimensionné et avec une API de recherche efficace.
Il a l'air d'avoir besoin de prefixes (j'ai toujours pas ete voir le jeu), auquel cas une hash table n'est pas particulierement adaptee.
Effectivement, si l'algorithme repose sur une recherche de prefixes, le hash est inadapté. Le probleme de Boggle a peut-etre une complexité supérieure au Scrabble, pour lequel un hash des combinaisons de lettres est a la base de programmes qui jouent des parties entières optimales en duplicate en une fraction de seconde.
-- Chqrlie.
candide
Charlie Gordon a écrit :
difficile de ne pas en faire. Ecrire un qsort sur une feuille blanche, qui fonctionne correctement du premier coup est une prouesse remarquable.
Certainement même si l'algo n'est pas très compliqué en soi. Je trouve plus ennuyeux encore un tri fusion.
Charlie Gordon a écrit :
difficile de ne pas en faire. Ecrire un qsort sur une feuille blanche, qui
fonctionne correctement du premier coup est une prouesse remarquable.
Certainement même si l'algo n'est pas très compliqué en soi. Je trouve
plus ennuyeux encore un tri fusion.