27.map,multimap及unordered_map, unordered_multimap

2.multimap

3.unordered_map

4.unordered_multimap

map

map特点

1.map支持下标访问符,即在[]中放入key,就可以找到与key对应的value

2.map通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树)

3.键的值相同的元素不能重复

map<string, size_t> people4{ {"Ann", 25}, {"Bill", 36}, {"Bill", 46}, {"Bill", 56},{"Jack", 32},{"Jill", 32} };
	for (auto e : people4) {
		cout << e.first << " " << e.second << endl;
	}
//out:
Ann 25
Bill 36
Jack 32
Jill 32

4.键的值无法修改,只能改变值

    map<string, size_t> people{ {"Ann", 25}, {"Bill", 46},{"Jack", 32},{"Jill", 32} };

	map<string, size_t>::iterator e = people.begin();
	e->second = 18;  //true
	e->first = "Niuniu";  //error

5.map会根据键排序,可以通过迭代器得到按键排序的结果(因为map底层的实现是红黑树)

    map<size_t, string> people{ {88, "Fuu"}, { 26, "Ann"}, {46, "Bill"},{ 32,"Jack"} };
	map<size_t, string>::const_iterator it = people.cbegin();
	while (it != people.cend()) {
		cout << it->first << " " << it->second << endl;
		it++;
	}
	cout << endl;
	/*out:
    	26 Ann
        32 Jack
        46 Bill
        88 Fuu
	*/

6.通过不存在的键访元素将会插入所访问的不存在的键值对,并且值给默认值

map<size_t, string> people{ {88, "Fuu"}, { 26, "Ann"}, {46, "Bill"},{ 32,"Jack"} };
	cout << people[64] << endl;  //不做边界检查,会插入pair(64,"\0")-->    通过不存在的键访元素将会插入所访问的不存在的键值对,并且值给默认值
	for (auto e : people)
		cout << e.first << " " << e.second << endl;
	cout << endl;
	
	/*out:
    	26 Ann
        32 Jack
        46 Bill
        64
        88 Fuu
    */

通过at()接口可以对边界做检查,不会导致插入不存在的元素, 访问键不存在的元素编译器会报错

map<size_t, string> people{ {88, "Fuu"}, { 26, "Ann"}, {46, "Bill"},{ 32,"Jack"} };
	cout << people。at(64) << endl;  //对边界做检查
	for (auto e : people)
		cout << e.first << " " << e.second << endl;
	cout << endl;
	
	/*out:
    	26 Ann
        32 Jack
        46 Bill
        88 Fuu
    */
map用法

map定义及初始化

1.定义一个空map

map<string, size_t> people1;

2.用初始化列表来指定 map 的初始值

map<string, size_t> people2{ {"Ann", 25}, {"Bill", 46},{"Jack", 32},{"Jill", 32} }; 

3.utility 头文件中定义了make_pair<T1,T2>()函数模板,它提供了一种组合 T1和T2类型对象的简单方法。因此,可以按如下方式创建 pair 对象来初始化 map:

map<string, size_t> people3{ make_pair("Ann",25),make_pair("Bill", 46),make_pair("Jack", 32),make_pair("Jill", 32) };

4.map<K,T> 模板定义了移动和拷贝构造函数,所以可以复制现有的容器

map<string, size_t> personnel1{ people2 };  //Duplicate people2 map

5.可以用另一个容器的一段元素来创建一个map,用开始和结束迭代器以通常的方式指定元素。显然,迭代器指向的pair元素的类型必须和容器兼容。

map<string, size_t> personnel2{ begin(people1),end(people1) };  
//people1.end();  等价于  end(people1)

6.当然,也可以用另一个容器的元素子集来创建容器:左闭右开[iterator1 , iterator2 )

    map<string, size_t>::iterator it1 = people2.begin();
	map<string, size_t>::iterator it2 = people2.find("Jack");

	map<string, size_t> personnel3{it1 , it2 };
	map<string, size_t>::iterator e = personnel3.begin();

插入

    map<string, size_t> people{ {"Ann", 25}, {"Bill", 46},{"Jack", 32},{"Jill", 32} };
    
    //首先定义一个pair
	pair<string, size_t> p("yang", 20);
	//然后插入,只能成功插入键值不同的元素(特性:map相同键值的元素不重复)
	people.insert(p);
	
	
	//或者
	people.insert(pair<string, size_t>("yang", 20));
	
	

	for (auto e : people) 
		cout << e.first << " " << e.second << endl;    

删除

1.直接通过键值删除元素

    people.erase("yang");

2.通过迭代器删除迭代器所迭代的元素

    map<string, size_t>::iterator it = people.find("yang");
	people.erase(it);

3.删除两个迭代器区间上的元素

    map<string, size_t>::iterator it1 = people.find("Bill");
	map<string, size_t>::iterator it2 = people.find("Jill");
	people.erase(it1, it2);

修改:通过[key]直接修改, 如果修改的键值对不存在则会插入

map<string, size_t> people{ {"Ann", 25}, {"Bill", 46},{"Jack", 32},{"Jill", 32} }; 
people[Ann] = 16;  //修改
people[yzy] = 20;  //插入

求容量及判空

    map<string, size_t> people{ {"Ann", 25}, {"Bill", 46},{"Jack", 32},{"Jill", 32} };
    
    //容量
	cout << people.size() << endl;  //4
	//判空
	cout << people.empty() << endl;  //0

清空

    map<string, size_t> people{ {"Ann", 25}, {"Bill", 46},{"Jack", 32},{"Jill", 32} };
    people.clear();
	cout << people.size() << endl;  //0

交换

    map<string, size_t> people1{ {"Ann", 25}, {"Bill", 46},{"Jack", 32},{"Jill", 32} };
	map<string, size_t> people2{ {"Fuu", 26}, {"Sansan", 32} };
	people1.swap(people2);

遍历

1.利用C++ auto

(1).不加const

    map<string, size_t> people{ {"Ann", 25}, {"Bill", 46},{"Jack", 32},{"Jill", 32} };

    for (auto e : people) {
		e.second = 16;
		cout << e.first <<" "<< e.second << endl;
	}
	cout << endl;
	/*out:
	    Ann 16
        Bill 16
        Jack 16
        Jill 16
	*/

	for (auto e : people) {
		cout << e.first << " " << e.second << endl;
	}
	cout << endl;
	/*out:
	    Ann 25
        Bill 46
        Jack 32
        Jill 32
	*/

实际上只是改变了输出结果

(1).加const

    map<string, size_t> people{ {"Ann", 25}, {"Bill", 46},{"Jack", 32},{"Jill", 32} };

    for (const auto e : people) {
		cout << e.first << e.second << endl;
		//e.second = 16;  //error
	}
	cout << endl;

auto关键字遍历的话,如果给auto关键字前面加上const,for (const auto e : people) 那么就无法通过e来修改值了

2.利用迭代器

(1).正向迭代器
map<string, size_t>::iterator

    map<string, size_t> people{ {"Ann", 25}, {"Bill", 46},{"Jack", 32},{"Jill", 32} };

    map<string, size_t>::iterator e = people.begin();
	while (e != people.end()) {
		cout << e->first << " "<< e->second<<endl;
		e++;
	}
	

(2).正向常迭代器, 不能通过迭代器修改值
map<string, size_t>::const_iterator

    map<string, size_t> people{ {"Ann", 25}, {"Bill", 46},{"Jack", 32},{"Jill", 32} };

    map<string, size_t>::const_iterator e = people.cbegin();
	//e->second = 17;  //error
	while (e != people.cend()) {
		cout << e->first << " " << e->second << endl;
		e++;
	}
	

(3).反向迭代器,可以通过迭代器修改值
map<string, size_t>::reverse_iterator

    map<string, size_t> people{ {"Ann", 25}, {"Bill", 46},{"Jack", 32},{"Jill", 32} };

    map<string, size_t>::reverse_iterator e = people.rbegin();  //可以通过迭代器修改值
	e->second = 16;
	while (e != people.rend()) {
		cout << e->first << " " << e->second << endl;
		e++;
	}

(4).反向常迭代器,不可以通过迭代器修改值
map<string, size_t>::const_reverse_iterator

    map<string, size_t> people{ {"Ann", 25}, {"Bill", 46},{"Jack", 32},{"Jill", 32} };

    map<string, size_t>::const_reverse_iterator e = people.crbegin();
	//e->second = 16;  //error
	while (e != people.crend()) {
		cout << e->first << " " << e->second << endl;
		e++;
	}

3.利用重载的运算符[]访问([]中是键, 返回值是值)

    map<string, size_t> people{ {"Ann", 25}, {"Bill", 46},{"Jack", 32},{"Jill", 32} };

	size_t age = people["Ann"];
	cout << age <<endl;
	cout << people["Bill"] << endl; 

auto关键字遍历的话,是用点访问键和值,迭代器的话是用箭头访问键和值

查找 时间复杂度为:

log_2 n

只能通过键值来查找,返回类型是迭代器

    map<string, size_t> people{ {"Ann", 25}, {"Bill", 46},{"Jack", 32},{"Jill", 32} };
    map<string, size_t>::iterator it3 = people.find("Ann");//找到就会返回迭代
    
    //error:不能通过键值对的值来查找
	map<string, size_t>::iterator it3 = people.find(25); 
	
	//找不到迭代器就会走到end()
	map<string, size_t>::iterator it4 = people.find("Fuu");
	if (it4 == end(people))
		cout << "not found" << endl;

multimap

#include

multimap特点(与map的区别是)

1.multimap在底层用二叉搜索树(红黑树)来实现。在内部,multimap中的元素总是通过其内部比较对象,按照指定的特定严格弱排序标准对key进行排序 的。

2.multiset容器通过key访问单个元素的速度通常比比unordered_multiset容器慢

3.键的值相同的元素可以重复

     pair<string, string> value[] = {
		{"111", "abc"},
		{"555","xyz"},
		{"222", "opq"},
		{"222", "opq"},
		{"222", "opq"}
	};
	multimap<string, string> multiMap;
	for (int i = 0; i < (sizeof(value) / sizeof(pair<string, string>)); i++) 
		multiMap.insert(value[i]);

	multimap<string, string>::iterator it = multiMap.begin();
	while (it != multiMap.end()) {
		cout << it->first << " ";
		cout<< it++->second << endl;
	}  
	
	/*out:
	    111 abc
        222 opq
        222 opq
        222 opq
        555 xyz
	*/

4.不可以以[key]的方式访问键值对的值

multimap用法与map相似

multimap定义及初始化(与map的定义及初始化方式一样)

容量及判空 清空 交换 遍历 都相似

插入:可以插入键的值相同的元素

删除:会删除键的值相同的所有元素

修改:不允许

    multimap<string, size_t> people{ {"Ann", 25},{"Ann", 18}, {"Bill", 46},{"Jack", 32},{"Jill", 32} };
	people["Bill"] = 100;  //error

查找:返回键值相同的元素中迭代顺序第一个的元素,找不到迭代器走到end()

	pair<string, string> value[] = {
		{"111", "abc"},
		{"555","xyz"},
		{"222", "opq"},
		{"222", "exo"},
		{"222", "nha"}
	};
	multimap<string, string> multiMap;
	for (int i = 0; i < (sizeof(value) / sizeof(pair<string, string>)); i++) 
		multiMap.insert(value[i]);
		
	multimap<string, string>::iterator find = multiMap.find("222");
	cout << find->first <<" "<< find->second <<endl;
	/*out:
    	222 opq
	*/
	
	multimap<string, string>::iterator find2 = multiMap.find("999");
	if (find2 == multiMap.end())
		cout << "Not found" << "iterator has pointed the end" << endl;
	/*out:
    	Not founditerator has pointed the end
	*/

unordered_map

#include <unordered_map>

unordered_map特点(与map的区别是)

1.在内部,unordered_map没有对<kye,value>按照任何特定的顺序排序,为了能在常数范围内找到key所对应的value,unordered_map将相同哈希值的键值对放在相同的桶中。

2.unordered_map容器通过key访问单个元素要比map快,但它通常在遍历元素子集的范围迭代方面效率较低。

3.unordered_maps实现了直接访问操作符(operator[]),它允许使用key作为参数直接访问value。若使用key作为参数直接访问value时,当不存在key对应的键值对时,就会插入值为默认值的键值对。

4.相较于map,unordered_map具有桶操作(map平衡化的红黑树, unordered_map哈希结构)

unordered_map用法

unordered_map定义及初始化(与map的定义及初始化方式一样)

1.定义一个空unordered_map

unordered_map<string, size_t> people1;

2.用初始化列表来指定 unordered_map 的初始值

unordered_map<string, size_t> people2{ {"Ann", 25}, {"Bill", 46},{"Jack", 32},{"Jill", 32} }; 

3.utility 头文件中定义了make_pair<T1,T2>()函数模板,它提供了一种组合 T1和T2类型对象的简单方法。因此,可以按如下方式创建 pair 对象来初始化 map:

unordered_map<string, size_t> people3{ make_pair("Ann",25),make_pair("Bill", 46),make_pair("Jack", 32),make_pair("Jill", 32) };

4.map<K,T> 模板定义了移动和拷贝构造函数,所以可以复制现有的容器

unordered_map<string, size_t> personnel1{ people2 };  //Duplicate people2 map

5.可以用另一个容器的一段元素来创建一个unordered_map,用开始和结束迭代器以通常的方式指定元素。显然,迭代器指向的pair元素的类型必须和容器兼容。

unordered_map<string, size_t> personnel2{ begin(people1),end(people1) };  
//people1.end();  等价于  end(people1)

6.当然,也可以用另一个容器的元素子集来创建容器:左闭右开[iterator1 , iterator2 )

    unordered_map<string, size_t>::iterator it1 = people2.begin();
	unordered_map<string, size_t>::iterator it2 = people2.find("Jack");

	unordered_map<string, size_t> personnel3{it1 , it2 };
	unordered_map<string, size_t>::iterator e = personnel3.begin();

插入 删除 容量及判空 清空 交换 查找都相似

遍历:只有正向的迭代器和正向的常迭代器

(1).正向的迭代器

    unordered_map<string, int> unorderedMap = { {"Ann", 25},{"Fuu", 18}, {"Bill", 46} };

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

(2).正向的常迭代器

    unordered_map<string, int> unorderedMap = { {"Ann", 25},{"Fuu", 18}, {"Bill", 46} };
	unordered_map<string, int>::const_iterator cit = unorderedMap.cbegin();
	while (cit != unorderedMap.cend()) {
		cout << cit->first << " ";
		cout<< cit++->second << endl;
	}

修改:

    unordered_map<string, int> unorderedMap = { {"Ann", 25},{"Fuu", 18}, {"Bill", 46} };
	unorderedMap["Ann"] = 24;

unordered_map的桶操作:

1.求桶的总个数

    unordered_map<string, string> unorderedMap;
	pair<string, string> val[] = {
		{"111", "aaa"},
		{"222", "bbb"},
		{"222", "ddd"},
		{"222", "uuu"},
		{"333", "ccc"},
		{"333", "fff"}
	};
	for (int i = 0; i < (sizeof(val) / sizeof(pair<string, string>)); i++) 
		unorderedMap.insert(val[i]);
		
//求桶的总个数
    cout<<"bucket cout: "<<unorderedMap.bucket_count()<<endl;

2.根据key值求元素在几号桶中

    cout << "find the  element in which bucket that key is ""333"" " << unorderedMap.bucket("333") <<endl;

3.求几号桶的size(元素个数)

    cout<<"one of the buckets size: "<<unorderedMap.bucket_size(0)<<endl;
    
    
     //访问所有桶的size
    for (int i = 0; i < unorderedMap.bucket_count(); i++) 
		cout << "buck["<< i<< "]" << "  size = " << unorderedMap.bucket_size(i) <<endl;

sizeof(pair<T1, T2>)大小

pair < {short, size_t, int, long}, { short, size_t, int, long } > //都是8
	pair < {string}, { short, size_t, int, long } >  //都是:32   string类不影响另一个(小于等于4的)类型字节对齐
   	//string 是28, long long 是8
   	sizeof(pair<string, string>) 是56
   	
	特殊: pair < string, long long >  //是: 40
	pair < {short, size_t, int, long}, long long >  //都是16  longlong会使short, size_t, int, long 都是8

unordered_multimap

#include <>

unordered_multimap特点(与multimap的区别是)

1.值可以重复,会将哈希值的键值对放在相同的桶中。unordered系列容器底层都使用了哈希结构,元素访问效率高

2.multimap都没有[key]访问元素的功能,也就是没有重载[]

unordered_multimap用法

定义及初始化(与multimap的定义及初始化方式一样)

插入(因为没用重载[],因此不能通过不存在的键值访问,从而插入元素)

删除 (会删除值相同的所有元素)

容量及判空 清空 交换 查找都相似

遍历:只有正向的迭代器和正向的常迭代器

(1).正向的迭代器

    unordered_multimap<string, string> unorderedMultiMap;
	pair<string, string> val[] = {
		{ "111", "aaa" },
		{ "222", "bbb" },
		{ "333", "ccc" },
		{ "444", "ddd"}	
	};
	for (int i = 0; i < (sizeof(val) / sizeof(pair<string, string>)); i++) 
		unorderedMultiMap.insert(val[i]);

    unordered_multimap<string, string>::iterator it = unorderedMultiMap.begin();
	//it->first = "888";  //error
	it->second = "uuu";
	while (it != unorderedMultiMap.end()) {
		cout << it->first << " ";
		cout << it++->second << endl;
	}
	cout << endl;

(2).正向的常迭代器

    unordered_multimap<string, string>::const_iterator cit = unorderedMultiMap.cbegin();
	//cit->first = "999";  //error
	//cit->second = "uuu";  //error
	while (cit != unorderedMultiMap.cend()) {
		cout << cit->first << " ";
		cout<< cit++->second << endl;
	}
	cout << endl;

修改:(由于没有对[]重载,因此只能通过迭代器来修改)
并且修改的值是哈希桶中第一个元素的值,并没有修改匹配的所有值。

    unordered_multimap<string, string>::iterator find = unorderedMultiMap.find("222");
	find->second = "kkk";

unordered_map的桶操作:

1.求桶的总个数

    unordered_multimap<string, string> unorderedMap;
	pair<string, string> val[] = {
		{"111", "aaa"},
		{"222", "bbb"},
		{"222", "ddd"},
		{"222", "uuu"},
		{"333", "ccc"},
		{"333", "fff"}    	};
	for (int i = 0; i < (sizeof(val) / sizeof(pair<string, string>)); i++) 
		unorderedMultiMap.insert(val[i]);
		
//求桶的总个数
    cout<<"bucket cout: "<<unorderedMultiMap.bucket_count()<<endl;

2.根据key值求元素在几号桶中

    cout << "find the  element in which bucket that key is ""333"" " << unorderedMultiMap.bucket("333") << endl;

3.求几号桶的size(元素个数)

    cout << "one of the buckets[0] size: " << unorderedMultiMap.bucket_size(0) << endl;
    
    
    //访问所有桶的size
    for (int i = 0; i < unorderedMultiMap.bucket_count(); i++)
		cout << "bucket[" << i << "]" << "  size = " << unorderedMultiMap.bucket_size(i) << endl;
发布了188 篇原创文章 · 获赞 65 · 访问量 8388

猜你喜欢

转载自blog.csdn.net/qq_43808700/article/details/105080621