【C++】-- STL之unordered_map/unordered_set详解

目录

一、map/set和unordered_map/unordered_set的区别

二、unordered_set

1.特点 

2.构造

(1)构造一个空的 unordered_set对象

(2) 用迭代器范围构造unordered_set对象

(3) 拷贝构造一个unordered_set对象

3.容量

(1)empty( )

(2)size( ) 

(3)max_size( ) 

4.迭代器

(1)begin( )

(2)end( )

5.查找

(1)find( )

(2)count( ) 

6.元素修改

(1)insert( )

(2)erase( )

(3)clear( )

(4)swap( )

三、 unordered_map

1.特点 

2.构造  

(1)构造一个空的unordered_map对象

(2)用迭代器范围构造unordered_set对象

(3)拷贝构造一个unordered_set对象

3.容量

(1)empty( )

(2)size( )

(3)max_size( )

4.迭代器

(1)begin( )

(2)end( ) 

5.元素操作符[ ]

6.查找

(1)find( ) 

(2)count( )

7.元素修改

(1)insert( )

(2)erase( )

(3)clear( )

(4)swap( )


一、map/set和unordered_map/unordered_set的区别

STL有两种容器:序列式容器和关联式容器,序列式容器vetor/lost/deque,用来存储数据。关联式容器map/set/unordered_map/unordered_set用来存储数据+查找数据。

unordered_map和unordered_set是c++里面两个提供哈希表的容器,map和set底层是红黑树,unordered_map和unordered_set的底层是哈希表(散列表),是一种映射。

对于set和unordered_set的增删查,在10000个数据、100000个数据、1000000个数据的情况下分别作了对比:

#include<iostream>
#include<vector>
#include<set>
#include<time.h>
#include<unordered_set>
using namespace std;

void test_unordered_set()
{
	vector<int> v;
	v.reserve(10000);//100000、1000000
	srand((unsigned int)time(NULL));

	for (int i = 0; i < 10000; i++)//100000、1000000
	{
		v.push_back(rand());
	}

	//插入
	set<int> s;
	size_t begin1 = clock();
	for (auto e : v)
	{
		s.insert(e);
	}
	size_t end1 = clock();

	unordered_set<int> us;
	size_t begin2 = clock();
	for (auto e : v)
	{
		us.insert(e);
	}
	size_t end2 = clock();

	cout << "set insert time:" << end1 - begin1 << endl;
	cout << "unorder_set insert time:" << end2 - begin2 << endl;

	//查找
	size_t begin3 = clock();
	for (auto e : v)
	{
		s.find(e);//set自带的查找效率是O(logn)
	}
	size_t end3 = clock();

	size_t begin4 = clock();
	for (auto e : v)
	{
		us.find(e); //unordered_set自带的查找,优点:使用哈希特性查找,效率高--O(1)
	}
	size_t end4 = clock();

	cout << "set find time:" << end3 - begin3 << endl;
	cout << "unorder_set find time:" << end4 - begin4 << endl;

	//删除
	size_t begin5 = clock();
	for (auto e : v)
	{
		s.erase(e);
	}
	size_t end5 = clock();

	size_t begin6 = clock();
	for (auto e : v)
	{
		us.erase(e);
	}
	size_t end6 = clock();

	cout << "set erase time:" << end5 - begin5 << endl;
	cout << "unorder_set erase time:" << end6 - begin6 << endl;
}

int main()
{

	test_unordered_set();

	return 0;
}

10000个数据的时间:

100000个数据的时间:

 

 1000000个数据的时间:

 可以看到,当数据量越大时,unordered_set相比于set所消耗的时间越少,这是因为unordered_set的底层是哈希表,增删查的效率更高。

二、 unordered_set

1.特点 

(1) unordered_map是存储<value, value>键值对的关联式容器,对value进行快速索引。
(2)在unordered_set中,元素的值同时是其键,是唯一标识,键和映射值的类型相同,键不可修改。unordered_set中的元素在容器不可修改,但是可以插入和删除元素。
(3)unordered_set中的元素不按任何特定顺序排序,而是根据其哈希值组织到存储桶中,允许直接根据value快速访问各个元素(平均时间复杂度是一定的)。
(4)unordered_set比set通过键访问单个元素的速度更快,但它通常在遍历元素子集的范围迭代方面效率较低。
(5)容器中的迭代器至少有正向迭代器。

2.构造

 有以下几种构造方式:

explicit unordered_set ( size_type n = /* see below */,
                         const hasher& hf = hasher(),
                         const key_equal& eql = key_equal(),
                         const allocator_type& alloc = allocator_type() );//构造空的unordered_set对象

template <class InputIterator>
         unordered_set ( InputIterator first, InputIterator last,
                         size_type n = /* see below */,
                         const hasher& hf = hasher(),
                         const key_equal& eql = key_equal(),
                         const allocator_type& alloc = allocator_type() );//用迭代器范围构造unordered_set对象

unordered_set ( const unordered_set& ust );//拷贝构造一个unordered_set对象

(1)构造一个空的 unordered_set对象

    unordered_set<int> us1;

向里面插入元素:

	us1.insert(2);
	us1.insert(72);
	us1.insert(6);
	us1.insert(35);
	us1.insert(291);
	us1.insert(327);

(2) 用迭代器范围构造unordered_set对象

用us1的迭代器范围构造us2: 

    unordered_set<int> us2(us1.begin(), us1.end());

(3) 拷贝构造一个unordered_set对象

 用us2拷贝构造us3:

    unordered_set<int> us3(us2);

3.容量

(1)empty( )

判断unordered_set是否为空:

cout << us3.max_size() << endl;

判断us3是否为空: 

    cout << us3.empty() << endl;//判断us3是否为空

 不为空:

(2)size( ) 

返回unordered_set中的元素个数

size_type size() const noexcept;

 求us3中的元素个数:

    cout << us3.size() << endl;

 

(3)max_size( ) 

返回unordered_set可存储的最大元素个数:

size_type max_size() const noexcept;

求us3最大元素个数 :

    cout << us3.max_size() << endl;

4.迭代器

(1)begin( )

返回迭代器开始: 

iterator begin() noexcept;

 返回us3迭代器开始:

    unordered_set<int>::iterator it = us3.begin();

(2)end( )

返回迭代器结尾:

iterator end() noexcept;

返回us3迭代器结尾: 

    us3.end();

5.查找

(1)find( )

如果找到元素就返回元素所在位置,否则返回元素结尾:

iterator find ( const key_type& k );

在us3中查找327: 

	unordered_set<int>::iterator ret = us3.find(327);
	if (ret != us3.end())
	{
		cout << "找到了" << endl;
	}
	else
	{
		cout << "没找到" << endl;
	}

 

(2)count( ) 

 统计容器中值为k的元素的个数:

size_type count ( const key_type& k ) const;

 统计us3中值为291的元素的个数:

    cout << us3.count(291) << endl;

 

6.元素修改

(1)insert( )

pair<iterator,bool> insert ( const value_type& val );//插入元素,成功返回的pair的第二个元素为true,失败则为false
iterator insert ( const_iterator hint, const value_type& val );//返回插入元素的位置
template <class InputIterator>
    void insert ( InputIterator first, InputIterator last );//插入一段区间
void insert ( initializer_list<value_type> il );//将列表作为元素插入容器中

①插入元素 

	cout << us2.insert(568).second << endl;//不存在,插入成功
	cout << us2.insert(291).second << endl;//已存在,插入失败

 

 ②返回插入元素的位置

    cout << *us2.insert(us3.begin(), 65) << endl;

 

③ 插入一段区间

    unordered_set<int> us2;
	us2.insert(us1.begin(), us1.end());
	unordered_set<int>::iterator it = us2.begin();
	while (it != us2.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;

 

④将列表作为元素插入容器中

	unordered_set<string> us4;
	us4.insert({ "int", "string", "float" });
	unordered_set<string>::iterator it = us4.begin();
	while (it != us4.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;

 

(2)erase( )

 删除元素:

iterator erase ( const_iterator position );//删除position位置的元素,并返回删除元素的位置
size_type erase ( const key_type& k );//返回删除值为k的元素的个数
iterator erase ( const_iterator first, const_iterator last );//删除从first到last区间的元素,并返回删除的last元素的位置

 ①删除position位置的元素,并返回删除元素的位置

	unordered_set<int> us2;
	us2.insert(us1.begin(), us1.end());
	cout << *us2.erase(us2.find(6)) << endl;

 

② 删除值为k的元素的,k存在返回1,k不存在返回0

    cout << us2.erase(72) << endl;

③ 删除从first到last区间的元素,并返回删除的last元素的位置

    cout << *us2.erase(us2.find(6), us2.find(291)) << endl;

 

(3)clear( )

 删除容器中所有元素

void clear() noexcept;

 清空us2中所有元素:

    us2.clear();

(4)swap( )

 交换两个同类型容器中的元素

unordered_set<int> us1;
	us1.insert(2);
	us1.insert(72);
	us1.insert(6);
	us1.insert(35);
	us1.insert(291);
	us1.insert(327);

	unordered_set<int> us5;
	us5.insert(56);
	us5.insert(57);
	us5.insert(58);
	us5.insert(59);
	us5.insert(60);
	us5.insert(61);

	us1.swap(us5);
	
	unordered_set<int>::iterator it1 = us1.begin();
	while (it1 != us1.end())
	{
		cout << *it1 << " ";
		it1++;
	}
	cout << endl;

	unordered_set<int>::iterator it5 = us5.begin();
	while (it5 != us5.end())
	{
		cout << *it5 << " ";
		it5++;
	}
	cout << endl;

 

哈系桶和哈希策略的函数等介绍完哈希表之后才能理解。

三、 unordered_map

1.特点 

(1)unordered_map是存储<key, value>键值对的关联式容器,允许通过key快速的索引到与其对应的value。
(2)在unordered_map中,键值通常用于惟一地标识元素,而映射value是一个对象,其内容与key关联。键和映射值的类型可能不同。
(3)unordered_map没有对<kye, value>按照任何特定的顺序排序, 为了能在常数范围内找到key所对应的value,unordered_map将相同哈希值的键值对放在相同的桶中。
(4)unordered_map容器通过key访问单个元素要比map快,但它通常在遍历元素子集的范围迭代方面效率较低。
(5)unordered_map实现了直接访问操作符(operator[]),它允许使用key作为参数直接访问value。
(6)容器中的迭代器至少有正向迭代器。

2.构造  

explicit unordered_map ( size_type n = /* see below */,
                         const hasher& hf = hasher(),
                         const key_equal& eql = key_equal(),
                         const allocator_type& alloc = allocator_type() );//构造空的unordered_map对象

template <class InputIterator>
  unordered_map ( InputIterator first, InputIterator last,
                  size_type n = /* see below */,
                  const hasher& hf = hasher(),
                  const key_equal& eql = key_equal(),
                  const allocator_type& alloc = allocator_type() );//用迭代器范围构造unordered_map对象

unordered_map ( const unordered_map& ump );//拷贝构造一个unordered_map对象

(1)构造一个空的unordered_map对象

    unordered_map<string, int> um1;

向里面插入元素:

    um1.insert(make_pair<string, int>("自行车", 8));
	um1.insert(make_pair<string, int>("消防车", 1));
	um1.insert(make_pair<string, int>("洒水车", 6));
	um1.insert(make_pair<string, int>("搅拌车", 7));
	um1.insert(make_pair<string, int>("小汽车", 5));

(2)用迭代器范围构造unordered_set对象

用um1的迭代器范围构造um2:

    unordered_map<string, int> um2(um1.begin(), um1.end());

(3)拷贝构造一个unordered_set对象

用um2拷贝构造um3:

    unordered_map<string, int> um3(um2);

3.容量

(1)empty( )

判断unordered_map是否为空: 

bool empty() const noexcept;

 判断um1是否为空: 

    cout << um1.empty() << endl;

 

(2)size( )

 返回unordered_map中的元素个数:

size_type size() const noexcept;

求um1中元素的个数:

    cout << um1.size() << endl;

 

(3)max_size( )

返回 unordered_map可存储的最大元素个数:

size_type max_size() const noexcept;

求um1最大元素个数 : 

    cout << um1.max_size() << endl;

 

4.迭代器

(1)begin( )

返回迭代器开始: 

iterator begin() noexcept;

 返回um1迭代器开始:

    unordered_map<string, int>::iterator it = um1.begin();

(2)end( ) 

返回迭代器结尾:

iterator end() noexcept;

 返回um1迭代器结尾:

    um1.end();

5.元素操作符[ ]

访问key为k的元素,如果存在就返回value的引用: 

mapped_type& operator[] ( const key_type& k );

 访问key为小汽车的元素,并返回小汽车对应的value的引用:

    cout << um1["小汽车"] << endl;

 

6.查找

(1)find( ) 

根据k返回k所在位置的迭代器,如果没找到就返回end

iterator find ( const key_type& k );

 查找洒水车:

    cout << um1.find("洒水车")->second << endl;

(2)count( )

 统计容器中key为k的元素的个数:

size_type count ( const key_type& k ) const;

 统计um1中key为"搅拌车"的元素个数:

    cout << um1.count("搅拌车") << endl;

 

7.元素修改

(1)insert( )

pair<iterator,bool> insert ( const value_type& val );//插入元素,成功返回的pair的第二个元素为true,失败则为false
iterator insert ( const_iterator hint, const value_type& val );//返回插入元素的位置
template <class InputIterator>
    void insert ( InputIterator first, InputIterator last );//插入一段区间
void insert ( initializer_list<value_type> il );//将列表作为元素插入容器中

 ①插入元素

	cout << um1.insert(make_pair<string, int>("大货车", 9)).second << endl;//不存在,插入成功
	cout << um1.insert(make_pair<string, int>("搅拌车", 1)).second << endl;//已存在,插入失败

 

  ②返回插入元素的位置

    cout << um1.insert(um1.begin(), make_pair<string, int>("扫地车", 10))->second << endl;

 

③ 插入一段区间 

    unordered_map<string, int> um2(um1.begin(), um1.end());
	unordered_map<string, int>::iterator it2 = um2.begin();

	while (it2 != um2.end())
	{
		cout << it2->first << ":" << it2->second << endl;
		it2++;
	}
	cout << endl;

 ④将列表作为元素插入容器中

    unordered_map<string, int> um3;    
    um3.insert({ { "摩托车",3 }, { "电动车",7 }});
	unordered_map<string, int>::iterator it3 = um3.begin();
	while (it3 != um3.end())
	{
		cout << it3->first << ":" << it3->second << endl;
		it3++;
	}
	cout << endl;

 

(2)erase( )

  删除元素:

iterator erase ( const_iterator position );//删除position位置的元素,并返回删除元素的位置
size_type erase ( const key_type& k );//返回删除值为k的元素的个数
iterator erase ( const_iterator first, const_iterator last );//删除从first到last区间的元素,并返回删除的last元素的位置

 ①删除position位置的元素,并返回删除元素的位置

删除搅拌车: 

    cout << um1.erase(um1.find("搅拌车"))->first << endl;

 

② 删除值为k的元素的,k存在返回1,k不存在返回0:

    cout << um1.erase("自行车") << endl;

 

③ 删除从first到last区间的元素,并返回删除的last元素的位置 

    cout << um1.erase(um1.find("消防车"), um1.find("扫地车"))->first << endl;

 

(3)clear( )

清空所有元素: 

void clear() noexcept;

 清空um1中所有元素:

    um1.clear();

(4)swap( )

交换两个同类型容器中的元素:

	unordered_map<string, string> um4;
	um4.insert(make_pair<string, string>("spring", "春天"));
	um4.insert(make_pair<string, string>("summer", "夏天"));
	um4.insert(make_pair<string, string>("autumn", "秋天"));
	um4.insert(make_pair<string, string>("winter", "冬天"));

	unordered_map<string, string> um5;
	um5.insert(make_pair<string, string>("east", "东"));
	um5.insert(make_pair<string, string>("south", "南"));
	um5.insert(make_pair<string, string>("west", "西"));
	um5.insert(make_pair<string, string>("north", "北"));

	um4.swap(um5);

	unordered_map<string, string>::iterator it4 = um4.begin();
	while (it4 != um4.end())
	{
		cout << it4->first << ":" << it4->second << endl;
		it4++;
	}
	cout << endl;

	unordered_map<string, string>::iterator it5 = um5.begin();
	while (it5 != um5.end())
	{
		cout << it5->first << ":" << it5->second << endl;
		it5++;
	}
	cout << endl;

 

 系桶和哈希策略的函数等介绍完哈希表之后才能理解。

猜你喜欢

转载自blog.csdn.net/gx714433461/article/details/126768864