2

在我的一個項目中,我使用樹實現,其中我使用容器 C=std::map<K,V>來維護每個樹節點的子項列表。每個樹節點都有一個唯一的名稱密鑰K,通常爲std::string容器模板參數std :: map或std :: vector

template<typename V, template<typename Key=std::string,typename Type=TreeNode<V>,typename ...> typename C> 
class TreeNode { 
    typedef C<std::string, Value> cont_type;  
    typedef V data_type; 

    cont_type childs; 
    data_type value; 

    cont_type::iterator genericFind(const K& k) { 
     // Something generic here!!! 
    } 
} 

這個實現對我來說工作得非常好,除了std :: map沒有考慮樹中插入的順序。對於某些應用程序,我需要保持插入的順序,但對於其他應用程序來說,快速信息反轉的需求更重要。

因此C必須要麼

std::vector<std::pair<K, V>> // keeping insertion order 

std::map<K,V> // fast information retrivial 

不,我有我的TreeNode類的實現問題,依然採用明確的std::map接口類型。尤其是,它使用的成員函數find,erase,insert需要被泛型替換,其中兩種容器類型的實現都非常具體。

例如childs.find(key)需要替換find(childs.begin(), childs.end(), key),只要我插入std::vector實現。

也許有另一種解決方案,我不知道。這可能是boost::multi_index,但我對此很不確定。

什麼可能是解決我的問題最簡單的方法?

+0

由於預取,向量可以非常快。不要把他們視爲「緩慢」。我建議(只是爲了科學)你也做矢量實現並測量你得到的性能差異。 – Hayt

+0

像這樣的東西可能會有所幫助:http://codereview.stackexchange.com/a/59999/42409 – Deduplicator

+0

由於一個是序列容器,另一個是關聯容器,希望找到任何接近對稱的東西都是非常希望的。無論如何,如果快速檢索真的出現在菜單上,請勿爲您的關聯容器折扣'unordered_map'。值得衡量。如果不是因爲你的「擦除」要求,我會建議只保留一個向量值*和*一個映射(你選擇的一種)映射向量索引的鍵,但是'擦除'會在游泳池。 – WhozCraig

回答

3

您可能創建專用的過載功能,並使用它們

template <typename Key, typename V> 
auto my_find(std::map<Key, V>& m, const Key& key) 
{ 
    return m.find(key); 
} 

template <typename Key, typename V> 
auto my_find(std::vector<std::pair<Key, V>>& v, const Key& key) 
{ 
    return std::find_if(v.begin(), v.end(), [&](const auto& p) { 
     return p.first == key; 
    }); 
} 
+0

該解決方案經過一些修改後適用於我。非常感謝。我必須對插入操作做同樣的事情,但我發現了一種常見的擦除方法。不幸的是,我需要四個查找函數來處理const和非const行爲。 – Aleph0

+0

@FrankSimon:我可以簡化爲'find'的3個函數:[Demo](http://coliru.stacked-crooked.com/a/38ab9aca2e7a262b)。 – Jarod42

+0

哇!我需要一些時間來消化這個。 :-) – Aleph0

2

創建具有相同的界面爲你想要的容器「選擇」通用包裝:

template <typename TKey, typename TValue> 
class my_map_wrapper 
{ 
private: 
    std::map<TKey, TValue> _map; 

public: 
    // Same interface as 'my_vector_wrapper'. 
    template <typename TEKey, typename TEValue> 
    void emplace(TEKey&& key, TEValue&& value) 
    { 
     _map.emplace(std::make_pair(std::forward<TEKey>(key), 
            std::forward<TEValue>(value))); 
    } 

    // ... 
}; 


template <typename TKey, typename TValue> 
class my_vector_wrapper 
{ 
private: 
    std::vector<std::pair<TKey, TValue>> _vec; 

public: 
    // Same interface as 'my_map_wrapper'. 
    template <typename TEKey, typename TEValue> 
    void emplace(TEKey&& key, TEValue&& value) 
    { 
     _vec.emplace_back(std::forward<TEKey>(key), 
          std::forward<TEValue>(value)); 
    } 

    // ... 
}; 

模板化的包裝本身你的樹節點類:

template <typename TWrapper> 
class TreeNode 
{ 
private: 
    TWrapper _container; 

public: 
    // Use "uniform" container interface... 
}; 

您現在可以定義方便類型別名在用戶代碼中的容器之間進行選擇:

template <typename TKey, typename TValue> 
using MapTreeNode = TreeNode<my_map_wrapper<TKey, TValue>>; 

template <typename TKey, typename TValue> 
using VectorTreeNode = TreeNode<my_vector_wrapper<TKey, TValue>>; 
+0

好點。但my_map_wrapper的第二個模板參數應該不是TValue,而是TreeNode <...>。現在我又迷了路。 – Aleph0

+0

非常感謝您的幫助。 Jarod42提出的方法更適合我的類。儘管我認爲你的看法更一般。但我只需要這兩個專業。 – Aleph0

+0

不客氣:) –