unordered_map和map类似,都是存储的key-value的值,可以通过key快速索引到value。不同的是unordered_map不会根据key的大小进行排序,

存储时是根据key的hash值判断元素是否相同,即unordered_map内部元素是无序的,而map中的元素是按照二叉搜索树存储,进行中序遍历会得到有序遍历。

所以使用时map的key需要定义operator<。而unordered_map需要定义hash_value函数并且重载operator==。但是很多系统内置的数据类型都自带这些,

那么如果是自定义类型,那么就需要自己重载operator<或者hash_value()了。

结论:如果需要内部元素自动排序,使用map,不需要排序使用unordered_map

map使用案例:

 

#include<string>  
#include<iostream>  
#include<map>  
  
using namespace std;  
  
struct person  
{  
    string name;  
    int age;  
  
    person(string name, int age)  
    {  
        this->name =  name;  
        this->age = age;  
    }  
  
    bool operator < (const person& p) const  
    {  
        return this->age < p.age;   
    }  
};  
  
map<person,int> m;  
int main()  
{  
    
person ps1("Tom1", 20);
    person ps2("Tom2", 22);
    person ps3("Tom3", 22);
    person ps4("Tom4", 23);
    person ps5("Tom5", 24);
    m.insert(make_pair(ps3, 100));
    m.insert(make_pair(ps4, 100));
    m.insert(make_pair(ps5, 100));
    m.insert(make_pair(ps1, 100));
    m.insert(make_pair(ps2, 100));

    std::string mpkey1("a1");
    std::string mpkey2("a2");
    std::string mpkey3("a3");
    std::string mpkey4("a4");
    std::string mpkey5("a5");
    mp.insert(make_pair(mpkey1, ps3));
    mp.insert(make_pair(mpkey1, ps4));    //出现重复,则不会更新,还是ps3
    mp.insert(make_pair(mpkey3, ps5));
    mp.insert(make_pair(mpkey4, ps1));
    mp.insert(make_pair(mpkey5, ps2));
    mp["a6"];    //生成一个"a6" value=默认值
    person& ps7 = mp["a7"];    //生成一个"a7",并且返回其second的引用。然后进行设置值
    ps7.age = 7;
    ps7.name = "name7";

    for (map<person, int>::iterator iter = m.begin(); iter != m.end(); iter++)
    {
        cout << iter->first.name << "\t" << iter->first.age << endl;
    }
    cout << "----" << endl;
    for (map<std::string, person>::iterator iter = mp.begin(); iter != mp.end(); iter++)
    {
        cout << (iter->second).name << "\t" << (iter->second).age << endl;
    }
 
      
    return 0;  
}

 

输出为:(根据age进行了排序的结果)

C++11 新特性: unordered_map 与 map 的对比_迭代器


因为Tom2和Tom3的age相同,由我们定义的operator<只是比较的age,所以Tom3覆盖了Tom2,结果中没有Tom2。

如果运算符<的重载是如下

bool operator < (const person &p)const{
    return this->name < p.name;  
}

输出结果: 按照 那么进行的排序,如果有那么相同则原来的那么会被覆盖

Tom1    20

Tom2    22

Tom3    22

Tom4    23

Tom5    24

 

unordered_map使用案例:

 

#include<string>  
#include<iostream>  
#include<unordered_map>  
using namespace std;  
  
struct person  
{  
    string name;  
    int age;  
  
    person(string name, int age)  
    {  
        this->name =  name;  
        this->age = age;  
    }  
  
    bool operator== (const person& p) const  
    {  
        return name==p.name && age==p.age;  
    }  
};  
  
size_t hash_value(const person& p)  
{  
    size_t seed = 0;  
    std::hash_combine(seed, std::hash_value(p.name));  
    std::hash_combine(seed, std::hash_value(p.age));  
    return seed;  
}  
  
int main()  
{  
    typedef std::unordered_map<person,int> umap;  
    umap m;  
    person p1("Tom1",20);  
    person p2("Tom2",22);  
    person p3("Tom3",22);  
    person p4("Tom4",23);  
    person p5("Tom5",24);  
    m.insert(umap::value_type(p3, 100));  
    m.insert(umap::value_type(p4, 100));  
    m.insert(umap::value_type(p5, 100));  
    m.insert(umap::value_type(p1, 100));  
    m.insert(umap::value_type(p2, 100));  
      
    for(umap::iterator iter = m.begin(); iter != m.end(); iter++)  
    {  
        cout<<iter->first.name<<"\t"<<iter->first.age<<endl;  
    }  
      
    return 0;  
}

 

对于hash_value的重载没有成功,在vs2013上报错。

详细介绍C++STL:unordered_map

不得不提一下,hash_map未加入在C++11标准中。

在VC中编译: 


1 #include <hash_map>2 using namespace stdext; 3 hash_map<int ,int> myhash;


 在GCC中编译:


1 #include <ext/hash_map>2 using namespace __gnu_cxx; 3 hash_map<int ,int> myhash;


既如此,还是用unordered_map吧!

 

C++ 11标准中加入了unordered系列的容器。unordered_map记录元素的hash值,根据hash值判断元素是否相同。map相当于java中的TreeMap,unordered_map相当于HashMap。无论从查找、插入上来说,unordered_map的效率都优于hash_map,更优于map;而空间复杂度方面,hash_map最低,unordered_map次之,map最大。

unordered_map与map的对比:

  存储时是根据key的hash值判断元素是否相同,即unordered_map内部元素是无序的,而map中的元素是按照二叉搜索树存储(用红黑树实现),进行中序遍历会得到有序遍历。所以使用时map的key需要定义operator<。而unordered_map需要定义hash_value函数并且重载operator==。但是很多系统内置的数据类型都自带这些。

  总结:结构体用map重载<运算符,结构体用unordered_map重载==运算符。

unordered_map与hash_map对比:

  unordered_map原来属于boost分支和std::tr1中,而hash_map属于非标准容器。
  unordered_map感觉速度和hash_map差不多,但是支持string做key,也可以使用复杂的对象作为key。
  unordered_map编译时gxx需要添加编译选项:--std=c++11

unordered_map模板:

template < class Key,                                    // unordered_map::key_type
           class T,                                      // unordered_map::mapped_type
           class Hash = hash<Key>,                       // unordered_map::hasher
           class Pred = equal_to<Key>,                   // unordered_map::key_equal
           class Alloc = allocator< pair<const Key,T> >  // unordered_map::allocator_type
           > class unordered_map;

迭代器:

unordered_map的迭代器是一个指针,指向这个元素,通过迭代器来取得它的值。

unordered_map<Key,T>::iterator it;
(*it).first;             // the key value (of type Key)
(*it).second;            // the mapped value (of type T)
(*it);                   // the "element value" (of type pair<const Key,T>)

它的键值分别是迭代器的first和second属性。 

it->first;               // same as (*it).first   (the key value)
it->second;              // same as (*it).second  (the mapped value)

成员函数:

=================迭代器========================= 
begin   返回指向容器起始位置的迭代器(iterator) 
end      返回指向容器末尾位置的迭代器 
cbegin    返回指向容器起始位置的常迭代器(const_iterator) 
cend    返回指向容器末尾位置的常迭代器 
=================Capacity================ 
size     返回有效元素个数 
max_size  返回 unordered_map 支持的最大元素个数 
empty        判断是否为空 
=================元素访问================= 
operator[]       访问元素 
at         访问元素 
=================元素修改================= 
insert    插入元素 
erase   删除元素 
swap    交换内容 
clear     清空内容 
emplace  构造及插入一个元素 
emplace_hint 按提示构造及插入一个元素 
================操作========================= 
find       通过给定主键查找元素,没找到:返回unordered_map::end
count      返回匹配给定主键的元素的个数 
equal_range   返回值匹配给定搜索值的元素组成的范围 
================Buckets====================== 
bucket_count    返回槽(Bucket)数 
max_bucket_count    返回最大槽数 
bucket_size       返回槽大小 
bucket       返回元素所在槽的序号 
load_factor     返回载入因子,即一个元素槽(Bucket)的最大元素数 
max_load_factor    返回或设置最大载入因子 
rehash       设置槽数 
reserve        请求改变容器容量

 插入元素示例:

// unordered_map::insert
#include <iostream>
#include <string>
#include <unordered_map>
using namespace std;

void display(unordered_map<string,double> myrecipe,string str)
{
    cout << str << endl;
    for (auto& x: myrecipe)
        cout << x.first << ": " << x.second << endl;
    cout << endl;
}

int main ()
{
    unordered_map<string,double>
    myrecipe,
    mypantry = {{"milk",2.0},{"flour",1.5}};

    /****************插入*****************/
    pair<string,double> myshopping ("baking powder",0.3);
    myrecipe.insert (myshopping);                        // 复制插入
    myrecipe.insert (make_pair<string,double>("eggs",6.0)); // 移动插入
    myrecipe.insert (mypantry.begin(), mypantry.end());  // 范围插入
    myrecipe.insert ({{"sugar",0.8},{"salt",0.1}});    // 初始化数组插入(可以用二维一次插入多个元素,也可以用一维插入一个元素)
    myrecipe["coffee"] = 10.0;  //数组形式插入

    display(myrecipe,"myrecipe contains:");

    /****************查找*****************/
    unordered_map<string,double>::const_iterator got = myrecipe.find ("coffee");

    if ( got == myrecipe.end() )
        cout << "not found";
    else
        cout << "found "<<got->first << " is " << got->second<<"\n\n";
    /****************修改*****************/
    myrecipe.at("coffee") = 9.0;
    myrecipe["milk"] = 3.0;
    display(myrecipe,"After modify myrecipe contains:");


    /****************擦除*****************/
    myrecipe.erase(myrecipe.begin());  //通过位置
    myrecipe.erase("milk");    //通过key
    display(myrecipe,"After erase myrecipe contains:");

    /****************交换*****************/
    myrecipe.swap(mypantry);
    display(myrecipe,"After swap with mypantry, myrecipe contains:");

    /****************清空*****************/
    myrecipe.clear();
    display(myrecipe,"After clear, myrecipe contains:");
    return 0;
}
/*
myrecipe contains:
salt: 0.1
milk: 2
flour: 1.5
coffee: 10
eggs: 6
sugar: 0.8
baking powder: 0.3

found coffee is 10

After modify myrecipe contains:
salt: 0.1
milk: 3
flour: 1.5
coffee: 9
eggs: 6
sugar: 0.8
baking powder: 0.3

After erase myrecipe contains:
flour: 1.5
coffee: 9
eggs: 6
sugar: 0.8
baking powder: 0.3

After swap with mypantry, myrecipe contains:
flour: 1.5
milk: 2

After clear, myrecipe contains:
*/
// unordered_map::bucket_count
#include <iostream>
#include <string>
#include <unordered_map>
using namespace std;

int main ()
{
    unordered_map<string,string> mymap =
    {
        {"house","maison"},
        {"apple","pomme"},
        {"tree","arbre"},
        {"book","livre"},
        {"door","porte"},
        {"grapefruit","pamplemousse"}
    };
    /************begin和end迭代器***************/
    cout << "mymap contains:";
    for ( auto it = mymap.begin(); it != mymap.end(); ++it )
        cout << " " << it->first << ":" << it->second;
    cout << endl;
    /************bucket操作***************/
     unsigned n = mymap.bucket_count();

    cout << "mymap has " << n << " buckets.\n";

    for (unsigned i=0; i<n; ++i)
    {
        cout << "bucket #" << i << "'s size:"<<mymap.bucket_size(i)<<" contains: ";
        for (auto it = mymap.begin(i); it!=mymap.end(i); ++it)
            cout << "[" << it->first << ":" << it->second << "] ";
        cout << "\n";
    }

    cout <<"\nkey:'apple' is in bucket #" << mymap.bucket("apple") <<endl;
    cout <<"\nkey:'computer' is in bucket #" << mymap.bucket("computer") <<endl;

    return 0;
}
/*
mymap contains: door:porte grapefruit:pamplemousse tree:arbre apple:pomme book:livre house:maison
mymap has 7 buckets.
bucket #0's size:2 contains: [book:livre] [house:maison]
bucket #1's size:0 contains:
bucket #2's size:0 contains:
bucket #3's size:2 contains: [grapefruit:pamplemousse] [tree:arbre]
bucket #4's size:0 contains:
bucket #5's size:1 contains: [apple:pomme]
bucket #6's size:1 contains: [door:porte]

key:'apple' is in bucket #5

key:'computer' is in bucket #6
*/