《C++面向对象程序设计》课程笔记 lessen9

1. 标准模板库 STL

1 关联容器:set、multiset、map、multimap

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

除了各容器都有的函数外,还支持以下成员函数: 

  • find:查找等于某个值的元素(x小于y和y小于x同时不成立即为相等)
  • lower_bound:查找某个下界
  • upper_bound:查找某个上界
  • equal_range:同时查找上界和下界
  • count:计算等于某个值的元素个数(x小于y和y小于x同时不成立即为相等)
  • insert:用以插入一个元素或一个区间 

2 multiset 

template<class Key, class Pred = less<Key>, class A = allocator<Key>>
class multiset
{
    ...
};
  •  Pred 类型的变量决定了 multiset 中的元素“一个比另一个小”是怎么定义的。multiset 运行过程中,比较两个元素 x,y 的大小的做法,就是生成一个 Pred 类型的变量,假定为 op,若表达式 op(x,y) 返回值为 true,则 x 比 y 小。Pred 的缺省类型是 less<Key>。less 模板是靠 “<” 来比较大小的。

  • find()、insert()(用于插入一个元素)、 lower_bound、upper_bound 时间复杂度都是 log(N)。
  • erase() 函数指向被删除元素的下一个元素的迭代器。当 erase 一个区间时左闭右开 [ first, last )。
  • lower_bound的区间:[begin(), it),这里注意 it 指向的值不比 val 小,返回的迭代器指向 it。
  • upper_bound的区间:[it, end()),这里注意 it 指向的值比 val 大,返回的迭代器指向 it。

2.1 multiset 的用法

#include <set>
using namespace std;
class A { };
int main()
{
	multiset<A> a;
	a.insert(A()); //error
}

multiset<A> a; 就等价于 multiset<A, less<A>> a; 插入元素时,multiset 会将被插入元素和已有元素进行比较。由于less模板是用“<”进行比较的。所以,这就要求 A 的对象能用 “<” 比较,即适当重载了 “<”

#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 & a2)
	{
		o << a2.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> MSET1; //MSET1用“<”比较大小
typedef multiset<A,MyLess> MSET2; //MSET2用 MyLess::operator ()比较大小

int main()
{
	const int SIZE = 6;
	A a[SIZE] = {4,22,19,8,33,40};
	MSET1 m1;
	m1.insert(a,a+SIZE);
	m1.insert(22);
	cout << "1) " << m1.count(22) << endl; //输出 1) 2
	cout << "2) ";
	Print(m1.begin(),m1.end()); //输出 2) 4 8 19 22 22 33 40
	//m1 元素:4 8 19 22 22 33 40
	MSET1::iterator pp = m1.find(19);
	if( pp != m1.end()) //条件为真说明找到
		cout << "found" << endl; //本行会被执行,输出 found
	cout << "3) ";
	cout << *m1.lower_bound(22) << "," << *m1.upper_bound(22) << endl; //输出 3) 22,33
	pp = m1.erase(m1.lower_bound(22),m1.upper_bound(22));
	//pp指向被删除元素的下一个元素
	cout << "4) ";
	Print(m1.begin(),m1.end()); //输出 4) 4 8 19 33 40
	cout << "5) " << *pp << endl;  //输出5) 33
	MSET2 m2;
	m2.insert(a,a+SIZE);
	cout << "6) ";
	Print(m2.begin(),m2.end()); //输出 6) 40 22 33 4 8 19

	system("pause");
	return 0;
}

3 set

template<class Key, class Pred = less<Key>, class A = allocator<Key>>
class set
{
	...
};
  • 插入 set 中已有的元素,忽略插入。

set 的用法示例: 

#include <iostream>
#include <set>
using namespace std;
int main()
{
	typedef set<int>::iterator IT;
	int a[5] = {3,4,6,1,2};
	set<int> st(a,a+5); //st里是 1 2 3 4 6
	pair<IT,bool> result;
	result = st.insert(5); //st变成 1 2 3 4 5 6   
	if(result.second) //插入成功则输出被插入元素
		cout << *result.first << "inserted" <<endl; //输出:5 inserted
	if(st.insert(5).second)
		cout << *result.first << endl;
	else
		cout << * result.first << "already exisis" << endl; //输出:5 already exisis
	pair<IT,IT> bounds = st.equal_range(4);
	cout << *bounds.first << "," << *bounds.second; //输出:4,5

	system("pause");
	return 0;
}

 4 预备知识: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) { }
};

//第三个构造函数用法示例
pair<int, int> p(pair<double,double> (5.5,4.6));
// p.first = 5, p.second = 4;

5 multimap

模板类:

template<class Key, class T, class Pred = less<Key>, class A = allocator<T>>
class multimap
{
	...
    typedef pair<const Key, T> value_type;
    ...
};  //Key 代表关键字的类型
  • multimap 中的元素由 <关键字,值> 组成,每个元素是一个 pair 对象,关键字就是 first 成员变量,其类型是 Key。 
  • multimap 中允许多个元素的关键字相同。元素按照 first 成员变量从小到大排列,缺省情况下用 less<Key> 定义关键字的 “小于” 关系。

 multimap 示例:

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

int main()
{
	typedef multimap<int,double,less<int>> mmid;
	mmid pairs;
	cout << "1) " << pairs.count(15) << endl;
	pairs.insert(mmid::value_type(15,2.7)); 
	//multimap 的类模板里有定义:typedef pair<const Key, T> value_type; value_type 即是 pair 对象
	pairs.insert(mmid::value_type(15,99.3));
	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 << ")" << ",";

	system("pause");
	return 0;
}

 multimap 示例2:

#include <iostream>
#include <map>
#include <string>
using namespace std;
class CStudent
{
public:
	struct CInfo //类的内部还可以定义类
	{
		int id;
		string name;
	};
	int score;
	CInfo info; //学生的其他信息
};
typedef multimap<int,CStudent::CInfo> MAP_STD;  //成绩用于查找和比较大小,故将成绩作为 Key。

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));
			//也可以写成 mp.insert(make_pair(st.score,st.info));
		}
		else if ( cmd == "Query" )
		{
			int score;
			cin >> score;
			MAP_STD::iterator p = mp.lower_bound(score);  //区间:[begin,it)
			if (p!=mp.begin())  // p==mp.begin()则未找到
			{
				--p;  //p的前一个分数才比score小
				score = p->first; //比要查询分数低的最高分
				MAP_STD::iterator maxp = p;
				int maxId = p->second.id;
				for(;p!=mp.begin()&&p->first==score;--p)
				{//遍历所有成绩和score相等的学生
					if (p->second.id > maxId)
					{
						maxp = p;     //更新分数最大学生的迭代器
						maxId = p->second.id;  //更新最大id
					}
				}
				if (p->first == score)
				{//如果上面循环是因为 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 //lower_bound的结果就是 begin,说明没人分数比查询分数低
				cout << "Nobody" << endl;
		}
		
	}
	system("pause");
	return 0;
}

6 map

模板类:

template<class Key, class T, class Pred = less<Key>, class A = allocator<T>>
class multimap
{
	...
    typedef pair<const Key, T> value_type;
    ...
};  //Key 代表关键字的类型
  • map 中的元素都是 pair 模板类对象。关键字(first 成员变量)各不相同。元素按照关键字从小到大排列,缺省情况下用 less<Key>,即 “<” 定义 “小于”。 
  •  map 的 [ ] 成员函数

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

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

map 示例:

#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));
	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 << ",";
	cout << endl;

	system("pause");
	return 0;
}

7 容器适配器 stack

  • stack 是后进先出的数据结构,只能插入、删除、访问栈顶的元素。
  • 可用 vector,list,deque来实现。缺省情况下,用 deque 实现。用 vector 和 deque 实现,比用 list 实现性能好。

stack 模板类:

template<class T, class Cont = deque<T> >
class stack
{
	...
};

stack 上可以进行以下操作:

                                           push          插入元素

                                           pop            弹出元素

                                           top             返回栈顶元素的引用

 8 容器适配器:queue

queue 模板类:

template<class T, class Cont = deque<T> >
class queue
{
	...
};
  • 和 stack 基本类似,可以用 list 和 deque 实现。缺省情况下用 deque 实现。
  • 同样也有 push,pop,top 函数。但是 push 发生在队尾,pop,top 发生在队头。先进先出。
  • 有 back 成员函数可以返回队尾元素的引用。(top队头,back队尾) 

9 容器适配器:priority_queue

priority_queue模板类:

template <class T, class Container = vector<T>, class Compare = less<T> >
class priority_queue
{
	...
};
  • 和  queue 类似,可以用 vector 和 deque 实现。缺省情况下用 vector 实现。
  • priority_queue 通常用堆排序技术实现,保证最大的元素总是在最前面。即执行 pop 操作时,删除的是最大元素;执行 top 操作时,返回的是最大元素的引用。默认的元素比较器是 less<T>。
  • push、pop 的时间复杂度 O(log(N))。top() 时间复杂度 O(1)。
#include <iostream>
#include <queue>
using namespace std;

int main()
{
	priority_queue<double> pq1;
	pq1.push(3.2);
	pq1.push(9.8);
	pq1.push(9.8);
	pq1.push(5.4);
	while( !pq1.empty() )
	{
		cout << pq1.top() << " ";
		pq1.pop();
	} //输出 9.8 9.8 5.4 3.2 
	cout << endl;
	priority_queue<double,vector<double>,greater<double> > pq2; //比大小用 greater,则数学上小的反而大
	pq2.push(3.2);
	pq2.push(9.8);
	pq2.push(9.8);
	pq2.push(5.4);
	while( !pq2.empty() )
	{
		cout << pq2.top() << " ";
		pq2.pop();
	} //输出 3.2 5.4 9.8 9.8

	system("pause");
	return 0;
}

容器适配器的元素个数:

stack,queue,priority_queue 都有:

                                                        empty()                成员函数用于判断适配器是否为空

                                                        size()                   成员函数返回适配器中元素个数

猜你喜欢

转载自blog.csdn.net/sinat_35483329/article/details/85617803