C++学习笔记(7)——标准模板库STL之set和map


以下介绍的都属于关联容器,关联容器是用平衡二叉树(红黑树)实现的,本篇不讨论红黑树。

零、pair类模板

pair与python中字典的键值对非常像。在C++中,pair的定义是:

template <typename T1, typename T2>
struct pair{
	T1 first;
	T2 second;
	...下面都是各种构造函数重载版本,不写了

可以不写参数:pair<string, double> p

可以写参数(常用):pair<string, double> p1("xiaoming", 78)

可以这样初始化:pair<string, double> p2(pair<string, double>("xiaoming", 78)),当这样写的时候,其实是用了定义中的函数模板,参数必须是pair模板类对象的引用。

也可以这样初始化:pair<string, double> p3 = make_pair("xiaoming", 78)

访问pair对象的“键”(Key):p.first

访问pair对象的“值”(Value):p.second

一、multiset和set

C++的set类似于python中的集合。只不过,python的集合中的元素都是不能重复的。

1.定义

使用multiset必须包含头文件set。mutilset类模板是这样定义的:

template <typename Key, typename Pred=less<Key>, typename B=allocator<Key>>
class multiset{...};

第一个参数:说明元素类型。

第二个参数:说明排序规则,实例化后的Pred可以是函数对象类,也可以是函数指针。这里默认的是less函数对象,定义如下:

template <typename T>
class less
{
	bool operator ()(const T &x, const T &y)const
	{ return x<y; }
};

事实上在STL中自带一些函数对象类模板,less是其中一个。STL中自带的函数对象类模板,可以书上查,可以网上查,这里不一一列举。

第三个参数极少用到,不写。

定义一个multiset容器对象:multiset <int> a;,等价于multiset <int, less<int>, allocator<int>> a;

2.实例

下面来看看我是怎么用的:

#include <iostream>
#include <set>
using namespace std;

class A{
	private:
		int n;
	public:
		A(int _n):n(_n){}
		friend class MyLess;
		friend bool MyLess(const A &a1, const A &a2);
		//需要对<进行重载,因为less函数对象类使用了<,会出现这样的语句a1<a2
		//若不进行解释,则编译出错
		friend bool operator < (const A &a1, const A &a2)
		{
			return a1.n < a2.n;
		}
		//需要对<<进行重载
		friend ostream &operator << (ostream &o, const A &a)
		{
			o << a.n;
			return o;
		}
};

class MyLess{ //用函数对象自定义了排序规则:按照个位数从小到大排序
	public:
		bool operator () (const A &a1, const A &a2)
		{
			return (a1.n % 10)<(a2.n % 10);
		}
};
//这里cout<<*first其实相当于是cout<<A,直接输出一个对象,
//所以,若不对<<进行重载,cout<<*first就无法解释了,编译会出错
template <typename T>
void Print(T first, T end)
{
	for(; first != end; ++first) cout<<*first<<" ";
	cout<<endl;
}

int main()
{
	const int SIZE = 7;
	A a[SIZE] = {4, 22, 19, 8, 33, 40, 67};
	multiset<A, less<A>> m1;//等价于multiset<A>,默认使用STL的less函数对象类模板
	multiset<A, MyLess> m2;//用我们自己定义的函数对象
	
	m1.insert(a, a+SIZE);
	Print(m1.begin(), m1.end());//4 8 19 22 33 40 67
	
	m2.insert(a, a+SIZE);
	Print(m2.begin(), m2.end());//40 22 33 4 67 8 19
	
	return 0;
}

注意,容器内的类型若是类,那么许多符号需要进行重载:<<、<、>、==、······等等。

3.常用成员函数

multiset自带的成员函数与vector和list很多重合,但是还有一些自己独有的,这里列举几个常用的:

m.insert(n); //将n插入容器中,返回其迭代器

m.erase(i); //删除i指向的元素,并返回后面一个元素的迭代器

m.erase(first, end); //删除区间[first, end),并返回迭代器last

m.find(first, last, n); //在容器[first, last)查找n,找到返回其迭代器,找不到返回last的迭代器。first和last可以省略

m.count(n); // 统计多少个元素的值与n相等

m.lower_bound(n); //查找一个最大位置it,使得[begin,it)中所有元素的关键字都比n小,返回值是迭代器it

m.upper_bound(n); //查找一个最小位置it,使得[it, end)中所有元素的关键字都比n大,返回值是迭代器it

m.equal_range(n); //同时求lower_bound和upper_bound,返回的是一个pair模板类对象x,x.first和x.second都是迭代器类型,前者是lower_bound,后者是upper_bound

注意,multiset和set中的find和count不是用“==”来比较相等的,而是遵循这样的原则:如果“x比y小”且“y比x小”同时为假,就认为x和y相等。

4.关于set

set和multiset类似,但是set不能有重复的元素。由于不能重复元素,所以set的insert函数与multiset的不同:

m.insert(n); //将n插入容器中,返回pair模板类对象x,若x.second=true,则说明插入成功,x.first=被插入元素的迭代器;若x.second=false,则说明已有该元素,x.first=已有元素的迭代器。

二、multimap和map

C++的map类似于python中的字典。

1.定义

使用multiset必须包含头文件set。mutilset类模板是这样定义的:

template <typename Key, typename T, typename Pred=less<Key>, typename B=allocator<Key>>
class map{
	...
	typedef pair<const Key, T> value_type;
	...
};

第一、二个参数:说明元素类型。

第三个参数:说明排序规则,实例化后的Pred可以是函数对象类,也可以是函数指针。这里默认的是less函数对象。

multimap的元素都是pair模板类的对象,first是关键字(key),second是值(value)。

2.实例

注意一个问题:输出map的时候,需要重载<<,这是因为,map的元素是pair对象,如果不进行重载<<,那么编译将出错。

#include<iostream>
#include<map>
using namespace std;

template <typename T1, typename T2>
ostream &operator<< (ostream &o, const pair<T1, T2> &p)
{
	o<<p.first<<": "<<p.second;
}

template <typename T>
void Print(T first, T end)
{
	for(; first != end; ++first) cout<<*first<<endl;
}

int main()
{
	typedef map<char, int, less<char>> MAP;
	MAP m;
	for(char i='a'; i<='e'; ++i)
		m.insert(MAP::value_type(i, i-96));
	Print(m.begin(), m.end());
	return 0;
}

输出结果:

a: 1
b: 2
c: 3
d: 4
e: 5

我这个程序写的是map哦!

3.常用成员函数

与set中的成员函数是一样的,这里不再阐述。不过insert中的参数必须是pair模板类对象。例如上面的程序:m.insert(MAP::value_type(i, i-96));

注意,multimap和map中的find和count不是用“==”来比较相等的,而是遵循这样的原则:如果“x比y小”且“y比x小”同时为假,就认为x和y相等。

4.关于map

set和multiset类似,但是set不能有重复的元素。

除了multimap的所有特点,map还有成员函数:T &operator[] (Key k)。例如上面的程序中,cout<<m['e']<<endl;将输出5,注意,这个方框里的是关键字(key)。

与set类似,map的insert函数也有这样的特性:

m.insert(n); //将n插入容器中,返回pair模板类对象x,若x.second=true,则说明插入成功,x.first=被插入元素的迭代器;若x.second=false,则说明已有该元素,x.first=已有元素的迭代器。

下一篇可能涉及容器适配器的内容。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值