STL-关联容器

5. 关联容器
(1)关联容器的特点
(1)容器需要存放对象和key值,key值与对象之间是一种映射关系。

(2)每个对象被存入到关联容器中时,会对key进行排序,进过比较后找到合适的
	位置后存放。因此key的数据类型需要提供排序方法,可以通过提供orerator<()
	或者Compare这两个函数进行比较。


(3)map只支持双向迭代器,因此不支持随机访问,虽然map支持[key]的方式访问对象,
	但是这并不是随机访问。



(2)关联容器分类
(1)map类:不允许key重复
(2)multimap类:map的特例,允许key重复
(3)set类:对象本身就是key值,不允许重复
(4)multiset类:set的特例,允许重复
	

(3)map的模板
前面的vector和list模板原本需要两个模板参数,但是实际上我们基本都只
指定第一个模板参数。

map类的模板参数比较多,总共有四个模板参数,map的类模板定义如下:
template < class Key, class T, class Compare = less,
       class Allocator = allocator > > class map;

(1)模板参数1:key值的类型
(2)模板参数2:key对应数据的类型
(3)模板参数3:用于排序时进行比较的函数对象类型
(4)模板参数4:用于在map中分配存储空间的函数类型

一般情况下,我们只需要指定前两个模板参数即可。

(4)定义一个map
(1)定义一个空的map
	std::map stumap;
	
	调用map的默认构造函数,定义一个空的map对象,第一个模板类型参数
	string表示key值的类型为string,第二个Student表示需要存储的对象
	是Student类型。

	但是实际上key和存放的对象的类型可以使任何类型。

(2)定义一个map,利用另一个map的袁元素进行初始化
	std::map stumap; 
	
	使用另一个map的[iter1, iter2)之间的元素初始化map。


(4)如何构建键值对
将key和对应对象构建成为键值对的方法有三个:
(1)std::make_pair("123", stu)
(2)std::map :: value_type("111",stu)
(3)std::pair("222",stu)

这三个函数在调用insert()插入新的键值对时很重要,比如:
enumMap.insert(map :: value_type("111", stu))
enumMap.insert(pair("222", stu));	



(5)访问map
(1)使用[]
	(1)作为右值:Student stu = stumap["111"];
		如果"111"对应的对象比更不存在,便会使用Student的默认构造函数创
		建一个Student对象。实际上只有确保"111"对应的对象存在才有意义。


	(2)作为左值:Stumap["222"] = stu;	
		作为左值时,如果"222"对应的键值对不存在,就创建一个新的键值对,
		然后将内容赋值为stu,利用这样的方式可以实现插入新键值对的操作,
		当然还可以使用insert()成员函数实现插入操作。		
	
		不管是作为左值还是右值,提前确定键值对是否存在非常关键,所以我
		们可以使用find成员函数先查找该key值对应的对象是否存在,存在就返
		回指向该位置的迭代器,然后使用该迭代器进行操作,否者就不操作。
	
	
(2)迭代器遍历
	(1)使用的是双向迭代器,不支持随机访问
	(2)正向迭代器需要用到begin()和end()函数
	(3)逆向迭代器rbegin()函数和rend()函数。
	(4)通过iter->second成员和iter->first成员就可以获取数据和键值key,
		second成员中存放的是数据,first存放的是键值。
		这里只能使用->,不能使用*和.操作。

(3)例子
	#include 
	#include 
	#include
	#include
	#include
	#include
	#include 

	using namespace std;
	class Student {
	public:
    		Student(const string name=" "):name(name) { }

    		string getname() const { return name; }
	private:
    		string name;
	};

	/* 使用迭代器遍历map */
	template  void show_map(Iter first, Iter last) {
    		for( ;first!=last; first++) {
            			/* 使用first访问键值,使用second访问对象,注意,通过迭代器访问到的
               		只是键值对,必须使用->访问first和second才能访问到具体的键值和对应数据,
               		由于存储的对象是地址,访问Student的name时,必须再次使用-> */
           		 cout << first->first<<"        "<< ((first)->second)->getname()< map1;

    		cout<< "使用[]做为左值插入新元素" < map2(++map1.begin(), --map1.end());

    		/* 使用逆向迭代起遍历 */
    		cout<< "显示map2中的元素" < insert ( const value_type& x );
       		iterator insert ( iterator position, const value_type& x );
		template 
  			void insert ( InputIterator first, InputIterator last );
  		(7)max_size()      返回可以容纳的最大元素个数
 		(8)size()          返回map中元素的个数
 		(9)swap()           交换两个map


(2)举例
	例子1:(1)—(5)函数举例	
	#include 
	#include 
	#include
	#include
	#include
	#include
	#include 

	using namespace std;
	class Student {
	public:
    		Student(const string name=" "):name(name) { }

    		string getname() const { return name; }
	private:
    		string name;
	};

	/* 使用迭代器便利map */
	template  void show_map(Iter first, Iter last) {
    		for( ;first!=last; first++) {
            		cout << first->first<<"        "<< ((first)->second)->getname()< map1;

    		cout<< "使用[]做为左值插入新元素" <getname()<
	#include 
	#include
	#include
	#include
	#include
	#include 

	using namespace std;
	class Student {
	public:
    		Student(const string name=" "):name(name) { }

    		string getname() const { return name; }
	private:
    		string name;
	};

	/* 使用迭代器便利map */
	template  void show_map(Iter first, Iter last) {
    		for( ;first!=last; first++) {
            		cout << first->first<<"        "<< ((first)->second)->getname()< map1;
    		std::map map2;

    		cout<< "使用[]做为左值插入新元素" <("345", new Student("bbbbbbb")));
    		map1.insert(map::value_type("456", new Student("ccccccc")));
    		map1.insert(map::value_type("567", new Student("ddddddd")));
    		show_map(map1.begin(), map1.end());

    		cout <<"\nmap1中可以容纳的最大元素个数:"<< map1.max_size()<
	#include 
	#include
	#include
	#include
	#include
	#include 

	using namespace std;
	class Student {
	public:
    		Student(const string name=" "):name(name) { }
    		string getname() const { return name; }
	private:
    		string name;
	};

	/* 使用迭代器便利map */
	template  void show_map(Iter first, Iter last) {
    		for( ;first!=last; first++) {
            		cout << first->first<<"        "<< ((first)->second)->getname()< map1;

    		cout <<"\n使用insert函数向map1中插入新元素"<("345", new Student("bbbbbbb")));
    		map1.insert(map::value_type("456", new Student("ccccccc")));
    		map1.insert(map::value_type("567", new Student("ddddddd")));
    		show_map(map1.begin(), map1.end());

    		cout <<"\n查找123对应的对象:"<< map1.max_size()<second)->getname() << endl;

    		cout <<"\nmap1中可以容纳的最大元素个数:"<< map1.max_size()<
	#include 
	#include
	#include
	#include
	#include
	#include 


	using namespace std;
	class Student { 
	public:
    		Student(const string name=" "):name(name) { } 

    		string getname() const { return name; }
	private:
    		string name;
	}
	
	/* 声明一个函数类类型,使用typedef为其定义一个别名 */
	typedef class Funclass {
	public:
    		void operator()(const Student &stu) {
            		cout<
	#include
	#include
	#include
	#include
	#include 

	using namespace std;
	class Student { 
	public:
    		Student(const string name=" "):name(name) { } 

    		string getname() const { return name; }
	private:
    		string name;
	}; 
			
	/* 声明一个函数类模板,使用typedef为其定义一个别名 */
	template class Funclass {
	public:
    		void operator()(const T &stu) {
            		cout< func1, Funclass &func2, Funclass *func3, const Student &stu){
    		cout << "通过函数对象调用实例化的函数" < func;//定义一个函数对象

    		/* 将函数对象作为参数进行传递
     		 *参数1:传递对象
      		*参数2:传递对象引用
      		*参数3:传递对象地址 */
    		display(func, func, &func, stu);

    		return 0;
	}

	运行结果:
	通过函数对象调用实例化的函数
	zhangsan

	通过函数对象引用调实例化的用函数
	zhangsan

	通过函数对象指针调用实例化的函数
	zhangsan

	例子分析:
	例子并没有做太大的改动,只是将函数类类型改成了函数类模板。

(3)给map自定义比较函数
  (1)给基本类型的key定义比较函数
	前面讲到,向map中插入数据时,map会自动调用默认的比较函数进行排序
	(默认的是升序排序)。

	但是map中的排序实在插入的时候进行的,目的是为插入的元素找到一个合
	适的位置,排序只在插入元素时进行,之后不能单独对map进行调用sort函
	数进行排序。

	但是map只对key为基本类型时,实现了默认的升序排序,如果希望对基本
	类型实现降序排序,或者想对非基本类型的key实现自定义类型排序,需要
	自己实现比较函数。

	如果比较函数返回true,小的在前,大的在后,这里的大小概念只是逻辑
	上的,不是数据的真实大小,我们完全可以定义数值大的为小,数值小的
	为大。

	通过map模板的第三个模板参数给map指定函数类类型或者函数类模板后,
	map会用它实例化一个比较函数。
	

	例子:对map中string类型key值进行降序排序
	#include 
	#include 
	#include
	#include
	#include
	#include
	#include 

	using namespace std;
	class Student { 
	public:
    		Student(const string name=" "):name(name) { } 

    		string getname() const { return name; }
	private:
    		string name;
	};     

	/* 使用迭代器便利map */
	template  void show_map(Iter first, Iter last) {
    		for( ;first!=last; first++) {
            		cout << first->first<<"        "<< ((first)->second)->getname()< class Funclass {
	public:
    		bool operator()(const T &op1, const T &op2) {
            		return op1 > op2;//按照从大到小比较
    		}
	};

	int main(void)
	{			
    		std::map map1;
    		/* 利用map的第三个模板参数指定用于比较函数的类模板,
     		* map会使用该函数类模板自动实例化一个比较函数,
     		* 如果该比较函数返回 */
    		std::map > map2;

    		map1["444"] = map2["444"] =  new Student("mnjnkkl");
    		map1["222"] = map2["222"] =  new Student("qqqqqqs");
    		map1["111"] = map2["111"] =  new Student("ddsfass");
    		map1["888"] = map2["888"] =  new Student("asdfdff");
    		map1["666"] = map2["666"] =  new Student("eqwewqe");
    		map1["555"] = map2["555"] =  new Student("sdfsfds");
    
    		cout<<"显示map1的内容"<
	#include 
	#include
	#include
	#include
	#include
	#include 

	using namespace std;
	class Stukey{
	public:
    		Stukey(int key=1):key(key) {}
    		int key;
	};

	class Student {
	public:
    		Student(const string name=" "):name(name) { }

    		string getname() const { return name; }
	private:
    		string name;
	};

	/* 使用迭代器便利map */
	template  void show_map(Iter first, Iter last) {
    		for( ;first!=last; first++) {
            		cout << (first->first).key<<"     "<< ((first)->second)->getname()< op2.key;//按照从大到小比较
    		}
	};

	int main(void)
	{
    		/* 如果不给map1和map2指定自定义的比较函数类
    		 * 类行或者模板,将无法通过编译 */
    		std::map map1;

    		/* 利用map的第三个模板参数指定比较函数类模板,
     		* map会使用该函数类模板自动实例化一个比较函数 */
    		std::map map2;

    		map1[Stukey(444)] = map2[Stukey(444)] =  new Student("mnjnkkl");
    		map1[Stukey(222)] = map2[Stukey(222)] =  new Student("qqqqqqs");
    		map1[Stukey(111)] = map2[Stukey(111)] =  new Student("ddsfass");
    		map1[Stukey(888)] = map2[Stukey(888)] =  new Student("asdfdff");
    		map1[Stukey(666)] = map2[Stukey(666)] =  new Student("eqwewqe");
    		map1[Stukey(555)] = map2[Stukey(555)] =  new Student("sdfsfds");

    		cout<<"显示map1的内容"<

你可能感兴趣的:(C++)