C++ std::unordered_map使用及如何自定义键的类型

C++ std::unordered_map使用及如何自定义键的类型

  • 头文件:

  • 定义:

      template,
    	   class _Pred = std::equal_to<_Key>,
    	   class _Alloc = std::allocator > >
        class unordered_map{...}
    
    _Hash = hash<_Key> 由于std::unordered_map 使用哈希算法,将值存储到桶中,如果自定义键的类型,需要实现对应方法。如果使用基本类型则不用提供
    _Pred = std::equal_to<_Key> 由于hash算法可能会遇到hash值相同,但内容不同的情况,提供函数来区分
    _Alloc = std::allocator > >则是内存管理使用,一般来说使用默认的内存管理即可
    
  • 公共定义的类型

    /// Public typedefs.
    typedef typename _Hashtable::key_type	key_type;  //键类型
    typedef typename _Hashtable::value_type	value_type; // std::Pair
    typedef typename _Hashtable::mapped_type	mapped_type;//值的类型
    typedef typename _Hashtable::hasher	hasher;
    typedef typename _Hashtable::key_equal	key_equal;
    typedef typename _Hashtable::allocator_type allocator_type;
    
  • 构造函数

    void testCreateMap(){
        using Group = std::unordered_map;
        Group a;  // 默认构造函数
        Group b{
          {1,"12"},{2,"22"}}; // c++11 初始化列表构造
        Group c(b.begin(),b.end()); // 两个迭代器
        Group d(std::move(b)); // 移动构造
        Group f(d); // 复制构造
        std::cout << "d size: " <<  d.size() << std::endl;
        for (const auto& item : d){
            std::cout << "key: "<< item.first << ",value: " << item.second << std::endl;
        }
    }
    结果:
    d size: 2
    key: 1,value: 12
    key: 2,value: 22
    
  • 插入、查找、遍历

    void test_insert_find_traverse(){
        // 使用重载的[]进行插入,查找
        // 问题是在查找时,比如例子中13键不存在,map会使用string的默认构造函数插入,这时map有两对pair {12,“sdf"},{13,""}
        using Group = std::unordered_map;
        Group a;
        a[12] = "use []";
        std::cout << a[12] << std::endl;
        std::cout << a[13] << std::endl;
        std::cout << a.size() << std::endl;
        std:: cout << "insert" << std::endl;
        // 使用insert 或emplace
        // insert 与 emplace 结果相同,返回的是std::pair,iterator是插入位置的迭代器,bool为是否从插入成功
        // iterator 的键为const类型 值可修改
        Group b{
          {12,"init"}};
        auto insert_result = b.insert(std::make_pair(12,"insert"));
        // 查看键值 由于 当前键已使用,插入失败
        std::cout << "if successful insert: " <<  (bool)insert_result.second
        << ", insert place: " << (*insert_result.first).first << ",value: " <<  (*insert_result.first).second << std::endl;
        // 修改值
        (*insert_result.first).second = "changed";
        // emplace 与insert功能相同,只是参数不用使用std::make_pair
        auto emplace_result = b.emplace(14,"emplace");
        for (const auto& item : b){
            std::cout << item.first  << " " << item.second << std::endl;
        }
        // 查找值
        //可以使用find(key)进行查找
        auto find_res = b.find(14);
        if (find_res != b.end()){
            // 查找成功
            std::cout << "found\n";
        } else{
            std::cout << "not found\n";
        }    
        // 遍历 希望遍历时修改值的值,可以使用这种方法,平时可以使用前面的方法
        for (auto item = b.begin();item != b.end();++item){
            item->second += "vvvvv";
            std::cout << "key: " << item->first << ", value: " << item->second << std::endl;
        }
    }
    结果
    use []
    
    2
    insert
    if successful insert: 0, insert place: 12,value: init
    14 emplace
    12 changed
    found
    key: 14, value: emplacevvvvv
    key: 12, value: changedvvvvv
    
  • 可以写一个模板函数来跳过[]查找引发的问题

    template 
    typename Map::mapped_type inline get_default(
            const Map& _map,
            const typename Map::key_type& key,
            const typename Map::mapped_type& dlft = typename Map::mapped_type()
            )
    {
        auto pos = _map.find(key);
        return (pos != _map.end() ? pos->second : dlft);
    }
    使用
    auto p = get_default(g,12);  
    auto p = get_default(g,12,"default");
    
  • 一个使用自定义键的例子

    class Position{
    private:
        int m_x = 0;
        int m_y = 0;
    public:
        int x() const { return m_x;}
        int y() const { return m_y;}
        Position(int _x,int _y) : m_x(_x),m_y(_y) {};
        // equal_to
        bool operator==(const Position& op) const { return m_x == op.m_x && m_y == op.m_y;}
    };
    
    // 定义hash函数
    template  inline void hash_combine(std::size_t &seed, const T &v){
        std::hash hasher;
        seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
    }
    // Position特定模板函数
    namespace std{
        template <> struct hash{
            size_t operator()(const Position& p) const{
                auto key = hash()(p.x());
                hash_combine(key,p.y());
                return key;
            }
        };
    }
    class Person{
    private:
        int m_age;
        std::string m_name;
    public:
        Person():m_age(0),m_name(){}
        Person(int _age,std::string _name) : m_age(_age),m_name(std::move(_name)){};
        int age() const { return m_age;}
        std::string name() const { return m_name;}
        bool empty(){ return m_age == 0 && m_name.empty();}
        void print(){std::cout << "age: " << m_age << ", name: " << m_name << std::endl; }
    };
    template 
    typename Map::mapped_type inline get_default(
            const Map& _map,
            const typename Map::key_type& key,
            const typename Map::mapped_type& dlft = typename Map::mapped_type()
            )
    {
        auto pos = _map.find(key);
        return (pos != _map.end() ? pos->second : dlft);
    }
    void testUnorderedMap(){
        using Group = std::unordered_map;
        Group a{
          {Position(1,2),Person(12,"adsf")}};
        auto result = a.insert(std::make_pair(Position(22,2),Person(22,"adddsf")));
        Group g(a.begin(),a.end());
        auto p = get_default(g,Position(1,2));
        if (p.empty()){
            std::cout << "not found" << std::endl;
        } else {
            p.print();
        }
    }
    int main(){
        testUnorderedMap();
        return 0;
    }
    结果
    age: 12, name: adsf
    

你可能感兴趣的:(c++,基础)