0

練習するために、私が再び慣れ親しんでいるトピックの1つは木です。深さ優先探索と幅優先探索の違いは、アルゴリズムをサポートするデータ構造の選択のみが異なることです。

テンプレートを使用してスタック(DFS)またはキュー(BFS)のいずれかにフィードする一般的なツリー検索を作成できると思いました。stack追加メンバーとqueue削除メンバーの名前が同じであるという点で十分です。残念ながら、アクセス関数は一度呼び出さtopfront、もう一方は呼び出されます。このため、私は自分が望む場所に完全に到着しませんでした。私はそのラムダなしでそれを行うことができませんでした:

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;
}
4

2 に答える 2

2

メンバー関数ポインターを必要な型にキャストできます。

mem_fun( static_cast< R (DataStructure::*)( Args... ) >( &DataStructure::top ) )

また

mem_fun( static_cast< R (DataStructure::*)( Args... ) const >( &DataStructure::top ) )

R結果の型とArgs...引数に適しています。

編集:完全な例で2つ(3つ)の間違いを犯しました:

a) キャストは正確である必要があります。つまり、正しい戻り値の型を提供する必要があります。幸いなことに、std::stackそれを支援する typedef があります。あなたの場合、次の 2 つのオプションでキャストできます。

typedef typename DataStructure::reference (DataStructure::*non_const_top)();
mem_fun( static_cast< non_const_top >( &DataStructure::top ) )

また

typedef typename DataStructure::const_reference (DataStructure::*const_top)() const;
mem_fun( static_cast< const_top >( &DataStructure::top ) )

b) を呼び出すときに、テンポラリを参照にバインドしようとしましたts。a) とともに、コードを次のように変更します。

DataStructure ds;
typedef typename DataStructure::reference (DataStructure::*non_const_top)();
return ts(tree, value, ds, mem_fun(static_cast<non_const_top>(&DataStructure::top)));

c)で、オブジェクトなしでtsを呼び出そうとします。getter次のように変更する必要があります。

auto const current = getter( &ds );

これらの変更により、コードは機能します。

于 2013-03-06T15:21:32.717 に答える
2

いくつかの typedef を次のように定義します。

typedef typename DataStructure::reference       reference;
typedef typename DataStructure::const_reference const_reference;

typedef reference (DataStructure::*top_type)();             //non-const version
typedef const_reference (DataStructure::*ctop_type)() const;//const version

その後、必要なものは何でも使用してください。

投稿されたコードでは、const バージョンが必要なので、次のように記述します。

mem_fun( static_cast<ctop_type>(&DataStructure::top ))

キャストは、コンパイラが使用するバージョンを選択するのに役立ちます。

ちなみに、C++11 ではstd::mem_fundeprecatedです。そして、 という別の機能が追加されましたstd::mem_fn。スペルの違いに注意してください。詳細については、次のトピックを参照してください。


必要なものは(or )std::bindではなくと呼ばれます:std::mem_funstd::mem_fn

それは今動作します:

あなたが呼び出している方法は、次のように呼び出しているため、getter必要であることを示唆しています:std::bindgetter

auto const current = getter();

getterが から返されたオブジェクトである場合、これはエラーですstd::mem_fun。この場合、次のように呼び出す必要があります。

auto const current = getter(&ds);

このデモを参照してください:

または、単純にメンバーへのポインターを渡す場合は、次のように呼び出します。

auto const current = (ds.*getter)();

参照 :オンラインデモ

3 つすべてを比較します。違いを見てください!

それが役立つことを願っています。

于 2013-03-06T15:24:22.887 に答える