标准模板库 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<y 与y<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_bound 和upper_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;
}