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() 成员函数返回适配器中元素个数