1. 程式人生 > >C++中的unordered_map,以及與STL中的map的比較

C++中的unordered_map,以及與STL中的map的比較

unordered_map是很早就知道的概念,但卻一直沒有認真去理解,單單以為它是Boost庫裡對map的實現,今天在做Leetcode的題目的時候,發現了使用它的優越性,索性翻開書,並查一查資料,把它大致搞個清楚,省的以後還要再查再找,浪費時間。

希望會有幫助,Bless~~

unordered_map是C++ Boost庫中的內容,這裡的unordered翻譯成“無序”。

但它並不是完全的“無序”的概念,而是雜湊式的儲存方式。

unordered庫提供了兩個雜湊對映類,unordered_map和unordered_multimap。

它們的介面、用法與STL裡的標準關聯容器map和multimap相同,但是內部實現不同。

它們用散列表代替了二叉樹的實現,模板引數多了雜湊計算函式,比較謂詞使用equal_to<>。

看到這裡,我們就應該明白,比起map/multimap,unordered_map和unordered_mutimap在查詢元素的時候,速度不是一般的快。

它們的查詢速率是常數級的,而map/multimap是基於二叉樹實現的,所以查詢是O(log n)的複雜度。下面,來看看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 uno

unordered_map屬於關聯式容器,採用std::pair儲存key-value形式的資料。用法與map一致。特別的是,STL中的map因為是有序的二叉樹儲存,所以對key值需要有大小的判斷,當使用內建型別時,無需過載operator < ;但是用使用者自定義型別的話,就需要過載啦! unoredered_map全程使用不需要比較元素的key值的大小,但是,對於元素的==要有判斷,又因為需要使用hash對映,所以,對於非內部型別,需要程式設計師為其定義這二者的內容,對於內部型別,就不需要了。

unordered庫使用“桶”來儲存元素,雜湊值相同的被儲存在一個桶裡。當雜湊容器中有大量資料時,同一個桶裡的資料也會增多,造成訪問衝突,降低效能。為了提高雜湊容器的效能,unordered庫會在插入元素是自動增加桶的數量,不需要使用者指定。但是,使用者也可以在建構函式或者rehash()函式中,指定最小的桶的數量。

從網上找資料的時候,發現了別人寫的關於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 p1("Tom1",20);
	person p2("Tom2",22);
	person p3("Tom3",22);
	person p4("Tom4",23);
	person p5("Tom5",24);
	m.insert(make_pair(p3, 100));
	m.insert(make_pair(p4, 100));
	m.insert(make_pair(p5, 100));
	m.insert(make_pair(p1, 100));
	m.insert(make_pair(p2, 100));	
	for(map<person, int>::iterator iter = m.begin(); iter != m.end(); iter++)
	{
		cout<<iter->first.name<<"\t"<<iter->first.age<<endl;
	}	
	return 0;
}
【unordered_map】
#include<string>
#include<iostream>
#include<boost/unordered_map.hpp>
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;
	boost::hash_combine(seed, boost::hash_value(p.name));
	boost::hash_combine(seed, boost::hash_value(p.age));
	return seed;
}
int main()
{
	typedef boost::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;
}
前者的輸出結果為:

Tom1    20
Tom3    22
Tom4    23
Tom5    24

後者的輸出結果為:

Tom1    20
Tom5    24
Tom4    23
Tom2    22
Tom3    22

以上內容參考了:

《Boost程式庫完全開發指南》和部落格 http://blog.csdn.net/orzlzro/article/details/7099231#

程式碼資料源自於:http://blog.csdn.net/orzlzro/article/details/7099231#

加油!