【问题标题】:Inserting typedef map into a hash table将 typedef 映射插入哈希表
【发布时间】:2011-10-01 16:52:14
【问题描述】:

在下面的程序中,我有一个typedef map。我想做的是实现一个哈希表。我正在尝试使用unordered_map,因为我听说这是有效的,因为它需要 O(1) 时间。我在我的主程序(我正在处理的另一个程序)中到处使用我的typedef map,所以我不想改变它。我想在其中一个函数中实现哈希表,我试图弄清楚如何将我的地图内容插入哈希表并稍后搜索密钥。我在两个遇到问题的地方插入了评论。请帮忙。

#include <iostream>
#include <vector>
#include <iterator>
#include <set>
#include <map>
#include <unordered_map>

using namespace std;

typedef vector<int> v_t;
typedef set<int> s_t;
typedef map<s_t, v_t> m_t;
typedef m_t::iterator m_it;
typedef std::unordered_map<s_t, v_t> Mymap;

int main(){
    m_t sample;
    for (int i = 0; i < 100; i = i+2) {
        v_t v;
        for(int k = 100 ; k<=105 ; ++k)
            v.push_back(k);
        s_t k;
        k.insert(i);
        sample.insert(sample.end(), make_pair(k, v));
    }

    //---------Debug--------------------
    for( m_it it(sample.begin()) ; it!=sample.end(); ++it) {
        cout << "Key: ";
        copy(it->first.begin(), it->first.end(), ostream_iterator<int>(cout, " "));
        cout << " => Value: ";
        copy (it->second.begin(),it->second.end(),ostream_iterator<double>(cout," "));
        cout << endl;
    }
    //---------------------------------

    Mymap c1;

    for( m_it it(sample.begin()) ; it!=sample.end(); ++it) {
        c1.insert(Mymap::value_type(it->first,it->second));   // how to do this ?
    }
    s_t s;
    s.insert(72);
    if(c1.find(s)!=c1.end())                                // does this work ?
        cout << "Success" << endl;
    return 0;
}

感谢任何帮助或 cmets。

阅读 Jason 的 cmets 后,我明白为什么我不能在 unordered_map 中使用 std::set 作为键,所以我尝试使用 std::string 作为键,但 find 功能不起作用。请你帮助我好吗。

Mymap c1;

for( m_it it(sample.begin()) ; it!=sample.end(); ++it) {
    v_t v1;
    std::string key;
    key.insert(key.begin(),it->first.begin(),it->first.end()); 
    copy(it->second.begin(), it->second.end(),std::back_inserter(v1));
    c1.insert(Mymap::value_type(std::make_pair(key,v1)));
}

string s = "72";
if((c1.find(s) != c1.end()) == true) 
    cout << "Success" << endl;
return 0;

【问题讨论】:

  • 确保您使用 C++0x 支持进行编译...这可能需要您使用 gcc 设置正确的标志,例如 gcc -std=c++0xgcc -std=gnu++0x ...您将还需要重新定义键值,因为如果不使用辅助函数,您无法直接将 int 转换为 string

标签: c++ map set hashtable unordered-map


【解决方案1】:

使这项工作缺少的基本元素是为您用作键的std::set 定义一个散列函数。 STL 已经为std::set 定义了相等性和字典顺序,因此您可以将其用作std::map 中的键值对,而不会出现任何问题。但是它没有定义散列函数,所以这是你必须通过重载 std::hash 来做的事情。这相当简单,可以通过定义以下函数来完成:

namespace std
{
    template<>
    struct hash<std::set<int> > : public std::unary_function<std::set<int>, size_t>
    {
        size_t operator()(const std::set<int>& my_set) const
        {
           //insert hash algorithm that returns integral type
        }
    };
}

上面的函子对象将返回一个整数类型size_t,并将std::set 作为参数。您必须在namespace std 中定义它,以便std::unordered_map 能够识别它。一个“简单”的算法可以简单地将元素相加,因为您有一组类型int。有更复杂的算法可以减少冲突的数量,这样一个简单的算法会以散列时间为代价而产生。但是,一旦定义了这个,将 std::set 键值插入 unordered_map 以及创建新的键值并在哈希表中查找它们应该不会有任何问题。

您可以在以下位置查看您的源代码示例:http://ideone.com/DZ5jm

编辑:Jason 的code 放在这里供参考:

#include <iostream>
#include <vector>
#include <iterator>
#include <set>
#include <map>
#include <unordered_map>

using namespace std;

namespace std
{
        template<>
        struct hash<set<int> > : public unary_function<set<int>, size_t>
        {
            size_t operator()(const std::set<int>& my_set) const
            {
               set<int>::iterator iter = my_set.begin();
               int total = 0;

               for (; iter != my_set.end(); iter++)
               {
                   total += *iter;
               }

               return total;
            }
        };
}



typedef vector<int> v_t;
typedef set<int> s_t;
typedef map<s_t, v_t> m_t;
typedef m_t::iterator m_it;
typedef std::unordered_map<s_t, v_t> Mymap;

int main(){

m_t sample;
for (int i = 0; i < 100; i = i+2) {
        v_t v;
        for(int k = 100 ; k<=105 ; ++k)
           v.push_back(k);
        s_t k;
        k.insert(i);
        sample.insert(sample.end(), make_pair(k, v));
    }

//---------Debug--------------------
for( m_it it(sample.begin()) ; it!=sample.end(); ++it) {
   cout << "Key: ";
   copy(it->first.begin(), it->first.end(), ostream_iterator<int>(cout, " "));
   cout << " => Value: ";
   copy (it->second.begin(),it->second.end(),ostream_iterator<double>(cout," "));
   cout << endl;
   }
//---------------------------------

Mymap c1;

for( m_it it(sample.begin()) ; it!=sample.end(); ++it) {
   c1.insert(Mymap::value_type(it->first,it->second));   // how to do this ?
   }
s_t s;
s.insert(72);
if(c1.find(s)!=c1.end())                                // does this work ?
   cout << "Success" << endl;
return 0;
}

【讨论】:

  • 我想我说它是有序的,是我弄错了。它不是,我会编辑它。但我仍然可以使用sample.find(s);map 中找到一个值,其中s 是程序中定义的std::set。我可以对unordered_map 做同样的事情吗?
  • 请注意:您可以在一组严格(弱)有序元素上定义严格(弱)排序:set1 &lt; set2 if *set1.begin() &lt; *set2.begin()。如果第一个(即最小的)元素相等,则可以迭代。如果所有元素都相等,则容器的长度相等,否则元素最少的容器更小。这是您将应用于数字的规范排序(不过是从右到左)。
  • 您也可以这样做,但同样,如果您将键值作为 指针 存储到您的集合中,您将不必担心上述规则您的键值相等......指向两个不同集合的指针不会相等(不能相等)这一事实为您提供了一种区分集合的好方法。此外,指针易于散列和排序,因此它们为std::mapstd::unordered_map 提供了很好的键值。为了防止内存泄漏,您可以将它们存储在 std::shared_ptr 中。
  • @bitmask ...是的,非常正确...对于按字典顺序排列字符串也可以这样做。我并不是想说它不能完成,而是它很麻烦……任何快速的技术都行不通。定义字典顺序可能是一个耗时的过程,而使用指针可以完全规避这个问题。
  • 如果您能举个例子或编辑我的代码,这将有助于我更好地理解。我真的很感激。
猜你喜欢
  • 2020-01-17
  • 2014-12-13
  • 2018-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多