标准模板库(STL)二:关联容器与容器适配器

标准模板库 STL

pair模板

template<class _T1, class _T2>
struct pair
{
  	typedef _T1 first_type;
  	typedef _T2 second_type;
  	_T1 first;
  	_T2 second;
  	pair():first(), second(){};
    //无参构造函数
  	pair(const _T1 &__a, const _T2 &__b):first(__a), second(__b) {}
  	template<class _U1, class _U2>
    pair(const pair<_U1, _U2 &__p):first(__p.first), second(__p.second) {}
    //用函数模板进行初始化
};
  • map/multimap 里放的都是pair模板类的对象,且按first从小到大排序

  • 第三个构造函数用法示例:

    pair<int, int>p(pair<double, double>(5.5, 4.6))`
    //p.first = 5
    //p.second = 4
    

关联容器

multiset

  • 内部元素有序排列
  • 新元素插入的位置取决于它的值
  • 查找速度快
  • 允许有重复元素

原型

template<class Key, class Pred = less<Key>, class A = allocator<Key> >
class multiset
{
  	...
};
//key决定了元素的类型
  • Pred类型的变量决定了multiset 中的元素,“一个比另一个小”是怎么定义的。 multiset运行过程中,比较两个元素x,y的大小的做法,就是生成一个 Pred类型的变量,假定为 op,若表达式op(x,y) 返回值为true,则 x比y小。 Pred的缺省类型是 less<Key>op可以是一个函数名字,函数指针或者函数对象,大多数情况下为函数对象。当其为函数对象是,op(x,y)是调用op这个对象的operator()成员函数。

less模板的定义

template<class T>
struct less : public binary_function<T, T, bool>
{
	bool operator()(const T &x, const T &y) const
{
	return x < y;
}
};//less模板是靠<来比较大小的
成员函数作用
iterator find(const T &val)在容器中查找值为val的元素,返回其迭代器。如果找不到,返回end()。注意此处的等于并不是直接使用==而是x<yy<x同时不成立
iterator insert(const T & val);将val插入到容器中并返回其迭代器。
void insert( iterator first,iterator last);将区间[first,last)插入容器。
iterator lower_bound(const T & val);查找一个最大的位置 it,使得[begin(),it) 中所有的元素都比 val 小。
iterator upper_bound(const T & val);查找一个最小的位置 it,使得[it,end()) 中所有的元素都比 val 大。
pair<iterator,iterator> equal_range(const T & val);同时求得lower_boundupper_bound。注意返回值pair类模板的
iterator erase(iterator it);删除it指向的元素,返回其后面的元素的迭代器(Visual studio 2010上如此,但是在 C++标准和Dev C++中,返回值不是这样)。
int count(const T &val)统计有多少个元素的值和val相等

插入元素时,multiset会将被插入元素和已有元素进行比较。由于less模板是用 < 进行 比较的,所以,这都要求对象能用 < 比 较,即适当重载了 <。注意,find insert upper_bound lower_bound的时间复杂度都是log(n)。而insert(区间)的时间复杂度为O(nlogn)

应用程序

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

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

class A
{
private:
	int n;
public:
	A(int n_) :n(n_) {}
	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;
	}
	friend class MyLess;
};

// 自定义比较对象函数
struct MyLess
{
	bool operator()(const A &a1, const A &a2)//重载圆括号
	{
		return (a1.n % 10) < (a2.n % 10);
        //按个位数比大小
	}
};

typedef multiset<A> MEST1; //MEST1用`<`比大小
typedef multiset<A,MyLess> MEST2; //MEST2用MyLess::operator()比较大小
int main()
{
	const int SIZE = 6;
	A a[SIZE] = { 4,22,19,8,33,40 };
	MEST1 m1; // 默认比较函数 less<A>
	m1.insert(a, a + SIZE);
	m1.insert(22);
	cout << "1)" << m1.count(22) << endl;
	cout << "2)";
	Print(m1.begin(), m1.end());
	MEST1::iterator i = m1.find(19);
	if (i != m1.end()) // true 表示找到
	{
		cout << "found" << endl;
	}
	cout << "3)" << *m1.lower_bound(22) << "," << *m1.upper_bound(22) << endl;
    //通过*把迭代器对应的元素
	i = m1.erase(m1.lower_bound(22), m1.upper_bound(22)); // 返回被删除元素的下一个元素的迭代器
	cout << "4)";
	Print(m1.begin(), m1.end());
	cout << "5)" << *i << endl;

	MEST2 m2;  // 自定义比较函数 MyLess
	m2.insert(a, a + SIZE);
	cout << "6)";
	Print(m2.begin(), m2.end());
	return 0;
}

set

原型

template<class Key, class Pred = less<Key>, class A = allocator<Key> >
class set
{
  	...
}
  • 不允许有重复元素,故插入已有元素时忽略插入(insert返回一个 pair
#include <iostream>
#include <set>
using namespace std;

int main()
{
	typedef set<int>::iterator IT;
	int a[5] = { 3,4,6,1,2 };
	set<int> myset(a, a + 5);//st: 1 2 3 4 6
	pair<IT, bool> result;
	result = myset.insert(5);
	if (result.second) //插曲成功则输出被插入的元素
	{
		cout << *result.first << " inserted" << endl;
	}
	if (myset.insert(5).second) //再次尝试插入5
	{
		cout << *result.first << endl;
	}
	else
	{
		cout << *result.first << " already exists" << endl;
	}
	pair<IT, IT> bounds = myset.equal_range(4);
	cout << *bounds.first << "," << *bounds.second << endl;
	return 0;
}

multimap

  • multimap中的元素由 <关键字, 值>组成,每个元素都是一个pair模板类的对象,关键字就是first,其类型为Key
  • multimap 中允许多个元素的关键字相同。元素按照first成员变量从小到大 排列,缺省情况下用 less<Key> 定义关键字的“小于”关系。
  • 元素的first成员变量不能被修改

原型

template<class Key, class T, class Pred = less<Key>, class A = allocator<T> >
class multimap
{
  	...
    typedef pair<const Key, T> value_type;
  	...
};

示例

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

int main()
{
	typedef multimap<int, double, less<int> > mmid;
	mmid pairs;
	cout << "1)" << pairs.count(15) << endl;//关键字等于15.输出0
	pairs.insert(mmid::value_type(15, 2.7));
    //mmid::value_type 把key替换成int, T替换成double,得到pair模板类。后面的参数对应构造函数,生成临时的对象。
    //typedef pair<const key, T>value_type;
    //要插入的元素必定是pair模板类的对象
    // pair<const Key, T>
	pairs.insert(mmid::value_type(15, 99.3));
    //Multimap允许有多个元素的first相同
	cout << "2)" << pairs.count(15) << endl;
	pairs.insert(mmid::value_type(30, 111.11));
	pairs.insert(mmid::value_type(10, 22.22));
	pairs.insert(mmid::value_type(25, 33.333));
	pairs.insert(mmid::value_type(20, 9.3));

	for (mmid::const_iterator i = pairs.begin(); i != pairs.end(); i++)
	{
		cout << "(" << i->first << "," << i->second << ")" << ",";
	}
	return 0;
}

关联容器很适合用于需要不断地更新数据,不断地在数据里面进行查询的过程。因为其在查询或者增删时,时间的复杂度均为O(log(n)).

#include<iostream>
#include<map>
#include<string>
using namespace std;
class  CStudent
{
public:
	struct CInfo //类的内部还可以定义类
	{
		int id;
		string name;
	};
	int score;
	CInfo info;//CInfo类型的对象作为成员变量
};

typedef multimap<int, CStudent::CInfo> MAP_STD;
int main() {
	MAP_STD mp;
	CStudent st;
	string cmd;
	while (cin >> cmd) {
		if (cmd == "Add") {
			cin >> st.info.name >> st.info.id >> st.score;
			mp.insert(MAP_STD::value_type(st.score, st.info));//pair模板类的对象来存放信息
    
		}
		else if(cmd == "Query")
		{
			int score;
			cin >> score;
			MAP_STD::iterator p = mp.lower_bound(score);
			if (p != mp.begin()) {//若为begin,说明查找不到
				--p; //返回值为左闭右开
				score = p->first;//比要查询分数低的最高分
				MAP_STD::iterator maxp = p;
				int maxid = p->second.id;
				for (; p != mp.begin() && p->first == score; --p) {
					if (p->second.id > maxid) {
						maxp = p;
						maxid = p->second.id;
					}
				}
				if (p->first == score) {
				//如果上面的循环是因为p==mp.begin()而停止,则p指向的元素也要被处理}
				//如果上面的循环是因为p==mp.begin()而停止,则p指向的元素也要被处理
					if (p->second.id > maxid) {
						maxp = p;
						maxid = p->second.id;
					}
				}
				cout << maxp->second.name << " " << maxp->second.id << " " << maxp->first << endl;
			}
			else
				cout << "Nobodz" << endl;
		}
	}
	return 0;
}

注意,

mp.insert(MAP_STD::value_type(st.score, st.info));
//也可以写作:
mp.insert(make_pair(st.score,st.info));

make_pair返回值是pair模板类

map

  • 关键字first各不相同

  • 若pairs为map模板类的对象,pairs[key]返回对关键字等于key的元素的值(second成员变量)的引用。若没有关键字为key的元素,则会往pairs里插入一个关键字为key的元素,其值用无参构造函数初始化,并返回其值的引用.

    map<int,double> pairs;
    pairs[50] = 5; //会修改pairs中关键字为50的元素,使其值变为50
    //若不存在关键字等于50的元素,则插入此元素,并使其值为5
    

示例

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

template <class Key, class Value> 
ostream& operator<<(ostream &o, const pair<Key, Value> &p)
{
	o << "(" << p.first << "," << p.second << ")";
	return o;
}

int main()
{
	typedef map<int, double, less<int> > mmid;//两个>>之间最好写一个空格,避免编译器无法识别
	mmid pairs;
	cout << "1) " << pairs.count(15) << endl;
	pairs.insert(mmid::value_type(15, 2.7));
	pairs.insert(make_pair(15, 99.3)); //make_pair生成一个pair对象
	cout << "2) " << pairs.count(15) << endl;
	pairs.insert(mmid::value_type(20,9.3));//如何判定insert是否成功,可以自己定义pair<interator,bool>
	mmid::iterator i;
	cout << "3) ";
	for (i = pairs.begin(); i != pairs.end(); i++)
	{
		cout << *i << ",";
	}
	cout << endl;
	cout << "4) ";
	int n = pairs[40];//如果没有关键字为40的元素,则插入一个.
    //其中第二个元素由无参构造函数进行初始化
	for (i = pairs.begin(); i != pairs.end(); i++)
	{
		cout << *i << ",";
	}
	cout << endl;
	cout << "5) ";
	pairs[15] = 6.28; //把关键字为15的元素值改成6.28
	for (i = pairs.begin(); i != pairs.end(); i++)
	{
		cout << *i << ",";
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值