Je suis occupé à convertir un code c++ en c. Heureusement, ce code est très peu "c++ specific" ( → code complet)
Là où je coince, c'est ici (pas sur les typedef ni sur make_pair(), ça c'est réglé) :
// Creating a shortcut for int, int pair type
typedef pair<int, int> Pair;
// Creating a shortcut for pair<int, pair<int, int>> type
typedef pair<double, pair<int, int>> pPair;
set<pPair> openList;
openList.insert(make_pair (0.0, make_pair (i, j)));
while (!openList.empty())
{
pPair p = *openList.begin();
// Remove this vertex from the open list
openList.erase(openList.begin());
C'est le set qui m'enquiquine. D'après ceci, dans openList, les éléments sont uniques (pas de souci) et triés.... mais sur quoi ?
Pour (les méthodes ?) .erase, .empty et .begin, je comprends, sauf l'écriture p=*openList.begin(): cela veut-il simplement dire que le contenu de la première position de openList est copié dans p ?
Je comprends bien le .insert, la pierre d'achoppement est, comme je l'ai écrit, sur quoi faut-il trier ?
D'avance merci pour vos lumières,
Edgar;
- Edité par edgarjacobs 19 mai 2018 à 22:16:37
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
On comprend mieux en lisant la documentation de C++
<<
Sets are containers that store unique elements following a specific order. (...) Internally, the elements in a <tt>set</tt> are always sorted following a specific strict weak ordering criterion indicated by its internal comparison object (of type <tt>Compare</tt>).
>>
C'est "set" de Pair, reste à trouver quel est le critère de comparaison pour ces bêtes là
ordre lexicographique : on regarde la première partie de la paire, puis la seconde si ce n'est pas suffisant.
----
ce que j'en comprends, en gros, c'est que l'algorithme commence par mettre un triplet <float,int,int> = {0.0, i, j} dans un conteneur, puis effectue une boucle
tant qu'il en reste {
prendre le plus petit triplet (dans l'ordre lexico)
faire des trucs avec, éventuellement en remettre
}
Autrement dit, quelque soit le type des élément que std::set pourra contenir, il s'attendra à (par défaut) ce qu'il existe un opérateur de comparaison bool operator < (type a, type b), mais tu restes tout à fait libre de fournir une fonction personnalisée qui permettra la comparaison de deux valeurs.
Il y a donc trois solutions:
Soit tu travaille sur des types primitif (char, short, int, long, long long, float, double, ou long double, ou les versions unsigned des types qui les supportent), pour lesquels l'opérateur < est frocément défini
soit tu travaille sur un type personnalisé pour lequel l'opérateur < est défini
soit tu travaille avec un type personnalisé et une fonction ou un foncteur qui permet la comparaison.
Par exemple, tu pourrais parfaitement avoir une structure proche de
struct MyStruct{
int id;
std::string name;
};
et disposer de deux foncteurs particuliers proche de
struct lessById{
bool operator()(MyStruct const & a, MyStruct const & b) const{
return a.id < b.id;
}
};
struct lessByName{
bool operator()(MyStruct const & a, MyStruct const & b) const{
return a.name < b.name;
}
}
et, si tu définis openList sous la forme de
std::set<MyStruct, lessById> openList;
les élément de openList seront trié par ordre croissant en fonction de la valeur de id alors que si tu le défini sous la forme de
std::set<MyStruct, lessByName> openList;
les élément de openList seront triés par ordre croissant en fonction de la valeur de name. Et, si, enfin, tu as un opérateur < disponible pour MyStruct, qui pourrait prendre la forme de
alors, tu pourrais tout aussi bien avoir déclaré openList sous la forme de
std::set<MyStruct> openList;
dont les éléments seraient triés par ordre croissant d'abord sur la valeur de name puis sur la valeur de id. C'est à dire que, si tu as des éléments de type MyStruct qui ressemblent à
Le premier cas te les triera dans l'ordre a < b < c, alors que le deuxième cas te les triera dans l'ordre c < b < a et que le troisième cas permet d'avoir des éléments ressemblant à
Si bien que le tri final commencera par comparer les double entre eux. Si ils sont égaux, il comparera le premier int de chaque élément, et la décision finale, si le premier int est également égal, reviendra au deuxième int.
En gros, c'est comme si tu avais créé une structure proche de
struct MaStruct{
double d;
int x;
int y;
};
avec un opérateur de comparaison défini sous la forme de
Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
Ceci dit, on est en C, et on ne peut pas surcharger operator<, ni passer des références.
Donc on va passer des adresses. Si on a vraiment besoin d'une collection ordonnée, c'est peut-être plus judicieux d'employer une fonction à la compareTo de Java, qui retourne un nombre négatif, nul ou positif selon que le premier est inférieur, égal ou supérieur
int compareStruct(struct MyStruct *s1,
struct MyStruct *s2) {
double dd = s1->d - s2->d;
if (dd < 0.0) return -1;
if (dd > 0.0) return 1;
int d = s1->x - s2->x;
if (d != 0) return d;
return s1->y - s2->y;
}
PS: j'ai regardé le code fourni pour A* : c'est du C déguisé en C++ (printf !) et mal programmé. Le type a répété le même code 8 fois, parce qu'il y a 8 directions.... Heureusement c'est pas un labyrinthe 3D, avec 26 déplacements possibles....
Déjà, quand je vois ça :
if (row == dest.first && col == dest.second)
return (true);
else
return (false);
ou
if (isValid (i, j+1) == true) {
....
}
j'ai une poussée de boutons.
En plus il raconte des trucs approximatifs :
sa closed list n'est pas une table de hachage, c'est une bête table 2D de marques.
en utilisant un tas de fibonacci, l'extraction du minimum, qui se fait autant de fois que l'insertion, ça va pas être en temps élémentaire,
PS: j'ai regardé le code fourni pour A* : c'est du C déguisé en C++ (printf !) et mal programmé. Le type a répété le même code 8 fois, parce qu'il y a 8 directions.... Heureusement c'est pas un labyrinthe 3D, avec 26 déplacements possibles....
Déjà, quand je vois ça :
if (row == dest.first && col == dest.second)
return (true);
else
return (false);
ou
if (isValid (i, j+1) == true) {
....
}
j'ai une poussée de boutons.
En plus il raconte des trucs approximatifs :
sa closed list n'est pas une table de hachage, c'est une bête table 2D de marques.
en utilisant un tas de fibonacci, l'extraction du minimum, qui se fait autant de fois que l'insertion, ça va pas être en temps élémentaire,
Tout à fait d'accord avec toi, mais dans un premier temps cela me suffira. J'ai un code fonctionnel, maintenant je vais passer à travers pour le rendre plus simple / plus propre (et peut-être plus rapide, mais ce n'est pas ma priorité). Il est certain que le coup des 8 blocs pour les 8 directions
Ça serait sympa de visualiser aussi les cases qui ont été mises dans l'openlist.
Ça donne une idée de la surface explorée. Normalement, un fuseau autour du chemin trouvé, + des égarements dans des impasses ou partant dans de mauvaises directions.
Ça serait sympa de visualiser aussi les cases qui ont été mises dans l'openlist.
Ça donne une idée de la surface explorée. Normalement, un fuseau autour du chemin trouvé, + des égarements dans des impasses ou partant dans de mauvaises directions.
My pleasure sir (toujours sans autoriser les diagonales) Mais il me semble que les cases de l'openlist sont fort éloignées du '"trajet optimal" - mais ne connaisant que très peu le sujet, je m'avance peut-être beaucoup.
- Edité par edgarjacobs 21 mai 2018 à 14:53:53
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
C'est très joli. Mais effectivement, ça a l'air de passer à beaucoup d'endroits pour trouver une solution. Il y a peut être beaucoup d'impasses, ceci dit. C'est difficile à voir.
J'ai effectivement été un peu trop rapide pour écrire ce code (ou, je pourrais faire valoir la fatigue peut-être ??? )
Je ne le modifie pas dans mon intervention originelle pour assumer mes erreurs, mais vous avez tout à fait raison
Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
C++ vers C : besoin d'une petite explication
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent