STL的unordered_map容器

1. 基本介绍

C++常用的无序关联容器unordered_map是C++11正式加入的对hash_map的官方实现(之前标准C++没有hash_map的官方实现,也就是说我们使用的STL的hash_map并不是官方的)。从名字可以看出这个结构是无序的,底层设计思想和STL的hash_map一样。元素在内部不以任何特定顺序排序,而是放进桶中。元素放进哪个桶完全依赖于其键的哈希。这允许对单独元素的快速访问,因为一旦计算哈希,则它准确指代元素所放进的桶。unordered_map搜索、插入和元素移除拥有平均常数时间复杂度

2. std::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;
  • key_type:第一个模板参数(Key)
  • mapped_type:第二个模板参数(T)
  • value_type:pair
  • hasher:第三个模板参数(Hash)
  • key_equal:第四个模板参数(Pred)

特性:

  • 关联性:std::unorederd_map 是一个关联容器,其中的元素根据键来引用,而不是根据索引来引用。
  • 无序性:在内部,std::unordered_map中的元素不会根据其键值或映射值按任何特定顺序排序,而是 根据其哈希值组织到桶中,以允许通过键值直接快速访问各个元素(常量的平均时间复杂度)。
  • 唯一性:std::unorederd_map中的元素的键是唯一的。

3. unordered_map 的初始化及常用函数

3.1 构造 std::unordered_map

示例:

// constructing unordered_maps
#include 
#include 
#include 

typedef std::unordered_map<std::string, std::string> stringmap;

stringmap merge(stringmap a, stringmap b) 
{
	stringmap temp(a);
	temp.insert(b.begin(), b.end());
	return temp;
}

int main() 
{
	stringmap first;                              // empty

	// 一个元素为:{key, value}
	stringmap second({ {"apple","red"}, {"lemon","yellow"} });       // init list
	stringmap third({ {"orange","orange"}, {"strawberry","red"} });  // init list
	stringmap fourth(second);                     // copy
	stringmap fifth(merge(third, fourth));        // move
	stringmap sixth(fifth.begin(), fifth.end());  // range

	std::cout << "sixth contains:" << std::endl;
	for (auto& x : sixth)
	{
		std::cout << x.first << ":" << x.second << std::endl;
	}
	std::cout << std::endl;

	return 0;
}

输出结果:

sixth contains:
orange:orange
strawberry:red
apple:red
lemon:yellow

3.2 赋值操作

复制:       unordered_map& operator= ( const unordered_map& ump );
移动:       unordered_map& operator= ( unordered_map&& ump );
初始化列表:  unordered_map& operator= ( intitializer_list<value_type> il );

示例:

// assignment operator with unordered_map
#include 
#include 
#include 

typedef std::unordered_map<std::string, std::string> stringmap;

stringmap merge(stringmap a, stringmap b) 
{
	stringmap temp(a);
	temp.insert(b.begin(), b.end());
	return temp;
}

int main() 
{
	//stringmap first, second, third;//此处连续定义三个会报错。
	stringmap  first = { { "AAPL", "Apple" }, { "MSFT", "Microsoft" } };  // init list
	stringmap second = { { "GOOG", "Google" }, { "ORCL", "Oracle" } };    // init list
	stringmap third = merge(first, second);      // move
	first = third;                               // copy

	std::cout << "first contains:" << std::endl;
	for (auto& elem : first)
	{
		std::cout << elem.first << ":" << elem.second << std::endl;
	}
	std::cout << std::endl;

	return 0;
}

输出结果:

first contains:
AAPL:Apple
MSFT:Microsoft
ORCL:Oracle
GOOG:Google

3.3 迭代器指向整个容器中的元素

即,“第一个”指整个容器中的第一个,“尾后”指整个容器中的尾后。

iterator begin() noexcept;                  //返回一个迭代器,指向第一个元素
const_iterator begin() const noexcept;      //返回一个迭代器,指向第一个元素

iterator end() noexcept;                    //返回一个迭代器,指向尾后元素
const_iterator end() const noexcept;        //返回一个迭代器,指向尾后元素

const_iterator cbegin() const noexcept;     //返回一个常量迭代器,指向第一个元素

const_iterator cend() const noexcept;       //返回一个常量迭代器,指向尾后元素

3.4 迭代器指向某个桶中的元素

即,“第一个”指某个桶中的第一个,“尾后”指某个桶中的尾后。

local_iterator begin( size_type n );             //返回一个迭代器,指向第n个桶内的第一个元素
const_local_iterator begin ( size_type n ) const;//返回一个迭代器,指向第n个桶内的第一个元素

local_iterator end(size_type n);                 //返回一个迭代器,指向第n个桶内的尾后元素
const_local_iterator end (size_type n) const;    //返回一个迭代器,指向第n个桶内的尾后元素

const_local_iterator cbegin( size_type n ) const;//返回一个常量迭代器,指向第n个桶内的第一个元素

const_local_iterator cend( size_type n ) const;  //返回一个常量迭代器,指向第n个桶内的尾后元素

示例:

// unordered_map::cbegin/cend example
#include 
#include 
#include 

int main() 
{
	std::unordered_map<std::string, std::string> mymap = { { "Australia", "Canberra" }, { "U.S.", "Washington" }, { "France", "Paris" } };

	std::cout << "mymap contains:" << std::endl;
	for (auto it = mymap.cbegin(); it != mymap.cend(); ++it)
		std::cout << it->first << ":" << it->second << std::endl;  // cannot modify *it
	std::cout << std::endl;

	std::cout << "mymap's buckets contain:\n";
	for (unsigned i = 0; i < mymap.bucket_count(); ++i) 
	{
		std::cout << "bucket #" << i << " contains:";
		for (auto local_it = mymap.cbegin(i); local_it != mymap.cend(i); ++local_it)
			std::cout << local_it->first << ":" << local_it->second;
		std::cout << std::endl;
	}
	
	return 0;
}

输出结果:

mymap contains:
Australia:Canberra
U.S.:Washington
France:Paris

mymap's buckets contain:
bucket #0 contains:
bucket #1 contains:Australia:Canberra
bucket #2 contains:France:Paris
bucket #3 contains:
bucket #4 contains:
bucket #5 contains:
bucket #6 contains:
bucket #7 contains:U.S.:Washington

3.5 容量操作

bool empty() const noexcept;          //unordered_map 是否为空
size_type size() const noexcept;      //获取unordered_map 中元素的数量

3.6 访问操作

  • 使用方括号([ ])
mapped_type& operator[] (const key_type& k);   //如果 k 匹配容器中某个元素的键,则该函数返回该映射值的引用。
mapped_type& operator[] (key_type&& k);        //如果 k 与容器中任何元素的键都不匹配,则该函数将使用该键 插入 一个新元素,并返回该映射值的引用。
  • 使用 at()
mapped_type& at (const key_type& k);             //如果 k 匹配容器中某个元素的键,则该函数返回该映射值的引用。  
const mapped_type& at (const key_type& k) const; //如果 k 与容器中任何元素的键都不匹配,则该函数将抛出 out_of_range 异常。

注意:const std::unordered_map 不能使用 operator[] 操作!!

示例:

// unordered_map::at
#include 
#include 
#include 

int main() 
{
	std::unordered_map<std::string, int> mymap = 
	{
		{ "Mars", 3000 },
		{ "Saturn", 60000 },
		{ "Jupiter", 70000 } 
	};

	mymap.at("Mars") = 3396;
	mymap.at("Saturn") += 272;
	mymap.at("Jupiter") = mymap.at("Saturn") + 9638;

	for (auto& x : mymap) 
	{
		std::cout << x.first << ": " << x.second << std::endl;
	}
	
	return 0;
}

输出结果:

Mars: 3396
Jupiter: 69910
Saturn: 60272

3.7 插入操作

// unordered_map::insert
#include 
#include 
#include 

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

	std::pair<std::string, double> myshopping("baking powder", 0.3);

	myrecipe.insert(myshopping);                        // copy insertion
	myrecipe.insert(std::make_pair<std::string, double>("eggs", 6.0)); // move insertion
	myrecipe.insert(mypantry.begin(), mypantry.end());  // range insertion
	myrecipe.insert({ { "sugar", 0.8 }, { "salt", 0.1 } });    // initializer list insertion

	std::cout << "myrecipe contains:" << std::endl;
	for (auto& x : myrecipe)
		std::cout << x.first << ": " << x.second << std::endl;

	std::cout << std::endl;
	
	return 0;
}

输出结果:

myrecipe contains:
baking powder: 0.3
flour: 1.5
eggs: 6
milk: 2
sugar: 0.8
salt: 0.1

3.8 删除操作

  • 根据元素位置
iterator erase (const_iterator position);     //返回一个迭代器,指向被删除元素的后一个元素
  • 根据元素的键
size_type erase (const key_type& k);          //返回被删除元素的数目,此处为1
  • 由一对范围迭代器指定删除的范围
iterator erase (const_iterator first, const_iterator last);  //返回一个迭代器,指向最后一个被删除元素的后一个元素
  • 删除所有元素
void clear() noexcept;

示例:

// unordered_map::erase
#include 
#include 
#include 

int main() {
	std::unordered_map<std::string, std::string> mymap;

	// populating container:
	mymap["U.S."] = "Washington";
	mymap["U.K."] = "London";
	mymap["France"] = "Paris";
	mymap["Russia"] = "Moscow";
	mymap["China"] = "Beijing";
	mymap["Germany"] = "Berlin";
	mymap["Japan"] = "Tokyo";

	// erase examples:
	mymap.erase(mymap.begin());      // erasing by iterator
	mymap.erase("France");             // erasing by key
	mymap.erase(mymap.find("China"), mymap.end()); // erasing by range

	// show content:
	for (auto& x : mymap)
	{
		std::cout << x.first << ": " << x.second << std::endl;
	}
	
	return 0;
}

输出结果:

U.S.: Washington
Russia: Moscow

3.9 查找操作

iterator find (const key_type& k);  
const_iterator find (const key_type& k) const;
//说明:在容器中搜索键值等于 k 的元素,如果找到,则返回一个指向该元素的迭代器,否则返回一个指向unordered_map :: end的迭代器。

示例:

// unordered_map::find
#include 
#include 
#include 

int main() {
	std::unordered_map<std::string, double> mymap = {
	   {"mom",5.4},
	   {"dad",6.1},
	   {"bro",5.9} };

	std::string input;
	std::cout << "who? ";
	getline(std::cin, input);

	// 查找
	std::unordered_map<std::string, double>::const_iterator got = mymap.find(input);

	if (got == mymap.end())
		std::cout << "not found";
	else
		std::cout << got->first << " is " << got->second;

	std::cout << std::endl;
	
	return 0;
}

输出结果:

who? mom
mom is 5.4

3.10 桶操作

size_type bucket_count() const noexcept;         //获取容器中桶的数目
size_type bucket_size ( size_type n ) const;     //获取第 n 个桶中元素的数量
size_type bucket ( const key_type& k ) const;    //获取键为 k 的元素所在桶的序号

你可能感兴趣的:(C++,c++,开发语言)