【发布时间】:2013-02-21 11:12:20
【问题描述】:
为了练习,我再次熟悉的主题之一是树。深度优先搜索和广度优先搜索的区别仅在于支持算法的数据结构的选择。
我想我可以编写一个通用的树搜索,我可以使用模板提供堆栈 (DFS) 或队列 (BFS)。 stack 和 queue 非常好,它们的添加和删除成员具有相同的名称。不幸的是,访问函数曾经被称为top,另一个被称为front。正因为如此,我没有完全到达我想要的地方。没有那个 lambda,我没办法做到:
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(); });
}
虽然我应该能够使用mem_fun(或mem_fun_ref)来提供相应的访问功能。我试过了
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));
}
然后编译器抱怨歧义(在const 和非const 版本之间)。
所以我搜索了互联网并得知我应该明确提供模板类型。
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));
}
遗憾的是,我想出的 ??? 的众多可能性都不能让编译器满意。
谁能给我一个提示?
更新:这是一个完整的工作示例(除非您定义 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;
}
【问题讨论】:
-
您能提供一个简短的完整示例吗?
-
顺便说一句,您将左值引用(
ts()中的D& ds)绑定到右值(dsf()中的DataStructure())。如果编译器接受它,那就不好了。你不应该这样做。 -
请注意,一般来说,将指针指向 C++ 库成员函数是不可移植的,因为库实现允许添加带有默认参数的附加参数。
标签: c++ templates generics mem-fun