Pour m'entraîner, l'un des sujets que je me familiarise à nouveau est celui des arbres. La chose à propos de la recherche en profondeur d'abord et de la recherche en largeur d'abord, c'est qu'ils ne diffèrent que par le choix de la structure de données qui soutient l'algorithme. J'ai pensé que je pourrais écrire une recherche commune d'arbre que je nourrirais une pile (DFS) ou une file d'attente (BFS) en utilisant des calibres. stack
et queue
sont assez gentils que leurs membres d'ajout et de suppression ont le même nom. Malheureusement, la fonction d'accès est une fois appelée top
et front
pour l'autre. Pour cette raison, je ne suis pas tout à fait arrivé là où je voulais. Je ne l'ai pas réussi à le faire sans que lambda:Comment puis-je résoudre cette ambiguïté par rapport à. mem_fun?
template<typename T, typename D, typename G>
bool ts(Tree<T> const & tree, T const value, D & ds, G getter)
{
if (empty(tree))
{
return false;
}
ds.push(tree.Root);
while (!ds.empty())
{
auto const current = getter();
ds.pop();
if (current->Value == value)
{
return true;
}
if (current->Left)
{
ds.push(current->Left);
}
if (current->Right)
{
ds.push(current->Right);
}
}
return false;
}
template<typename T>
bool dfs(Tree<T> const & tree, T const value)
{
stack<typename Tree<T>::Node const * const> ds;
return ts(tree, value, ds, [&ds](){ return ds.top(); });
}
template<typename T>
bool bfs(Tree<T> const & tree, T const value)
{
queue<typename Tree<T>::Node const * const> ds;
return ts(tree, value, ds, [&ds](){ return ds.front(); });
}
Je pensais que je devrais pouvoir utiliser mem_fun
(ou mem_fun_ref
) pour assurer la fonction d'accès respectif. J'ai essayé
template<typename T>
bool dfs(Tree<T> const & tree, T const value)
{
typedef stack<typename Tree<T>::Node const * const> DataStructure;
return ts(tree, value, DataStructure(), mem_fun(&DataStructure::top));
}
Mais le compilateur se plaint ambiguousity (entre un const
et une version non const
).
J'ai donc cherché les internets et appris que je devrais fournir le type de modèle explicitement.
template<typename T>
bool dfs(Tree<T> const & tree, T const value)
{
typedef stack<typename Tree<T>::Node const * const> DataStructure;
return ts(tree, value, DataStructure(), mem_fun</*???*/>(&DataStructure::top));
}
Malheureusement, aucune des nombreuses possibilités pour ??? que je pourrais trouver satisfait le compilateur.
Quelqu'un peut-il me donner un indice?
Mise à jour: Voici un exemple de travail complet (sauf si vous définissez NO_LAMBDA):
#include <iostream>
#include <stack>
#include <functional>
using namespace std;
template<typename T>
struct Tree
{
struct Node
{
T Value;
Node * Left;
Node * Right;
Node(T value) : Value(value), Left(nullptr), Right(nullptr) {}
virtual ~Node()
{
if (Left) delete Left;
if (Right) delete Right;
}
};
Node * Root;
Tree() : Root(nullptr) {}
virtual ~Tree() { if (Root) delete Root; }
};
template<typename T> void insert(typename Tree<T>::Node * node, T const & value)
{
typename Tree<T>::Node ** selected = &(value < node->Value ? node->Left : node->Right);
if (*selected)
insert(*selected, value);
else
*selected = new typename Tree<T>::Node(value);
}
template<typename T> void insert(Tree<T> & tree, T value)
{
if (!tree.Root)
tree.Root = new typename Tree<T>::Node(value);
else
insert(tree.Root, value);
}
template<typename T, typename D, typename G>
bool ts(Tree<T> const & tree, T const value, D & ds, G getter)
{
if (!tree.Root) return false;
ds.push(tree.Root);
while (!ds.empty())
{
auto const current = getter();
ds.pop();
if (current->Value == value) return true;
if (current->Left) ds.push(current->Left);
if (current->Right) ds.push(current->Right);
}
return false;
}
template<typename T>
bool dfs(Tree<T> const & tree, T const value)
{
typedef typename Tree<T>::Node const * DataStructureContent;
typedef stack<DataStructureContent> DataStructure;
#ifdef NO_LAMBDA // With this defined, it breaks.
return ts(tree, value, DataStructure(),
mem_fun(static_cast<DataStructureContent (DataStructure::*)() const>(&DataStructure::top)));
#else // This works.
DataStructure ds;
return ts(tree, value, ds, [&ds]() { return ds.top(); });
#endif
}
int main()
{
Tree<int> tree;
insert(tree, 5);
insert(tree, 2); insert(tree, 1); insert(tree, 3);
insert(tree, 7); insert(tree, 6); insert(tree, 9);
cout << "DFS(7) -> " << dfs(tree, 7) << endl;
cout << "DFS(8) -> " << dfs(tree, 8) << endl;
return 0;
}
Pourriez-vous produire un court exemple complet? –
Btw, vous liez une référence lvalue ('D & ds' dans' ts() ') à un rvalue (' DataStructure() 'dans' dsf() '). Si le compilateur l'accepte, c'est mauvais. Tu ne devrais pas le faire. –
Remarque en général, prendre des pointeurs vers les fonctions membres de la bibliothèque C++ n'est pas portable, car les implémentations de bibliothèques sont autorisées à ajouter des paramètres supplémentaires avec des arguments par défaut. – aschepler