C++:容器?破瓶烂罐子!

一. 顺序容器:vector、deque、list

1.1 vector

1.1.1 成员函数:insert、erase

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

template<class T>
void PrintVector(T s, T e){
	for(; s != e; ++s)
		cout << * s << " ";
	cout << endl;
}


int main(){
	int a[5] = {1, 2, 3, 4, 5};
	vector<int> v(a, a+5);
	cout << "1) " << v.end() - v.begin() <<endl;	//随机迭代器可以相减
	//输出:1) 5
	cout << "2) ";	PrintVector(v.begin(), v.end());
	//输出:2) 1 2 3 4 5 
	v.insert(v.begin() + 2, 13); 	//在begin() + 2处插入13 
	cout << "3) ";	PrintVector(v.begin(), v.end());
	//输出:3) 1 2 13 3 4 5  
	v.erase(v.begin() + 2);	//删除位于begin() + 2的元素
	cout << "4) ";	PrintVector(v.begin(), v.end()); 
	//输出: 4) 1 2 3 4 5
	vector<int> v2 (4, 100);	//v2有4个元素,都是100
	v2.insert(v2.begin(), v.begin()+1, v.begin()+3);
	//将v的一段插入v2开头
	cout << "5) v2: ";	PrintVector(v2.begin(), v2.end());
	//输出: 5) v2: 2 3 100 100 100 100 
	v.erase(v.begin()+1, v.begin()+3);
	//删除v上的一个区间,即 2, 3
	cout << "6) ";	PrintVector(v.begin(), v.end());
	//输出:  6) 1 4 5 
	return 0;
} 

1.1.2 用vector实现二维数组

  1. 实现方式:
vector<vector<int> > v(3);
//v有3个元素,每个元素都是vector<int>容器

TIPS:int后面的>>中间要加一个空格,防止编译器识别为右移运算符

  1. 实例:
#include <vector>
#include <iostream>
using namespace std;

int main(){
	vector<vector<int> >  v(3);
	for(int i=0; i<v.size(); ++i)
		for(int j=0; j<4; ++j)
			v[i].push_back(j);
			//v[i]是一个 vector<int> 容器
	for(int i=0; i<v.size(); ++i){
		for(int j=0; j<v[i].size(); ++j)
			cout << v[i][j] << " ";
		cout <<endl; 
	}
	return 0;
} 
  • 输出结果:
0 1 2 3
0 1 2 3
0 1 2 3
//3个vector<int>:0 1 2 3

1.2 deque

  1. 所有适用于vector的操作都适用于deque
  2. deque还有 push_front(将元素插入到前面) 和 pop_front(删除最前面的元素) 操作,复杂度是 O(1)

1.3 list(双向链表)

1.3.1 了解了解

  1. 在任何位置插入删除都是常数时间,不支持随机存取

1.3.2 成员函数

除具有所有顺序容器都有的成员函数外,还支持:

成员函数功能
push_front在前面插入
pop_front删除前面的元素
sort排序(list不支持STL的算法sort:需要随机存取)
remove删除和指定值相等的所有元素
unique删除所有和前一个元素相同的元素(要做到元素不重复,则unique之前还需要sort)
merge合并两个链表,并清空被合并的那个
reverse颠倒链表
splice在指定位置前面插入另一个链表中的一个或多个元素,并在另一链表中删除被插入元素
  • 应用实例
#include <list>
#include <iostream>
#include <algorithm>
using namespace std;

class A{
	private:
		int n;
	public:
		A(int n_){n = n_;}
		friend bool operator < (const A & a1, const A & a2);
		friend bool operator == (const A & a1, const A & a2);
		friend ostream & operator << (ostream & o, const A & a);
};

bool operator < (const A & a1, const A & a2){
	return a1.n < a2.n;
}

bool operator == (const A & a1, const A & a2){
	return a1.n == a2.n;
}

ostream & operator << (ostream & o, const A & a){
	o << a.n;
	return o;
}

template<class T>
void PrintList(const list<T> & lst){
//参数为链表的引用 
//不推荐,还是用两个迭代器作参数好(即(T s, T e))
	typename list<T>::const_iterator i;
	i = lst.begin();
	for(i = lst.begin(); i != lst.end(); i++)
		cout << * i << ",";
}
//typename用来说明list<T>::const_iterator是一个类型
//devcpp中定义类型不确定的迭代器需要加typename,而在vs中不用 

int main(){
	list<A> lst1, lst2;
	
	lst1.push_back(1);	lst1.push_back(3);
	lst1.push_back(2);	lst1.push_back(4);
	lst1.push_back(2);
	lst2.push_back(10);	lst2.push_front(20);
	lst2.push_back(30);	lst2.push_back(30);
	lst2.push_back(30);	lst2.push_front(40);
	lst2.push_back(40);
	cout << "1) ";	PrintList(lst1);	cout <<endl;
	//1) 1, 3, 2, 4, 2,
	cout << "2) ";	PrintList(lst2);	cout <<endl;
	//2)  40, 20, 10, 30, 30, 30, 40, 
	
	lst2.sort();
	cout << "3) ";	PrintList(lst2);	cout <<endl;
	//3) 10, 20, 30, 30, 30, 40, 40,
	
	lst2.pop_front();
	cout << "4) ";	PrintList(lst2);	cout <<endl;
	//4) 20, 30, 30, 30, 40, 40,
	
	lst1.remove(2);	//删除所有和A(2)相等的元素
	cout << "5) ";	PrintList(lst1);	cout <<endl;
	//5)  1, 3, 4,
	
	lst2.unique();	//删除所有和前一个元素相等的元素
	cout << "6) ";	PrintList(lst2);	cout <<endl;
	//6) 20, 30, 40, 
	
	lst1.merge(lst2);	//将lst2合并到lst1,并清空lst2
	cout << "7) ";	PrintList(lst1);	cout <<endl;
	//7) 1, 3, 4, 20, 30, 40,
	cout << "8) ";	PrintList(lst2);	cout <<endl;
	//8)
	
	lst1.reverse();
	cout << "9) ";	PrintList(lst1);	cout <<endl;
	//9)  40, 30, 20, 4, 3, 1, 
	
	lst2.push_back(100);	lst2.push_back(200);
	lst2.push_back(300);	lst2.push_back(400);
	list<A>::iterator p1, p2, p3;
	p1 = find(lst1.begin(), lst1.end(), 3);
	p2 = find(lst2.begin(), lst2.end(), 200);
	p3 = find(lst2.begin(), lst2.end(), 400);
	lst1.splice(p1, lst2, p2, p3);
	//将[p2, p3)插入p1之前,并从lst2中删除[p2, p3)
	cout << "10) ";	PrintList(lst1);	cout <<endl;
	//10)  40, 30, 20, 4, 200, 300, 3, 1
	cout << "11) ";	PrintList(lst2);	cout <<endl;
	//11)  100, 400, 
	return 0;
} 

二. 关联容器:set / multiset、map / multimap

2.1 了解了解

  1. 自动保持内部有序,查找速度快
  2. 除了各容器都有的函数外,还支持以下函数:
函数功能
find查找等于某个值的元素(x小于y和y小于x同时不成立即为相等)
lower_bound查找某个下界
upper_bound查找某个上界
equal_range同时查找上界和下界
count计算等于某个值的元素个数(x小于y和y小于x同时不成立即为相等)
insert用以插入一个元素或一个区间

2.2 pair模板

pair定义在<utility>内,包含在<map>

  • 定义:
pair<typeName1, typeName2> name;
pair<string, int> p;
  • 初始化:
pair<string, int> p("str", 5);
  • 临时创建一个pair,用于赋值给map等…
pair<string, int>("str", 5);
make_pair("str", 5);
  • code:
template<class _T1, class _T2>
struct pair{
	typedef _T1 first_type;
	typedef _T2 second_type;
	_T1 first;
	_T2 second;
	pair():first(),second(){}
	//①无参构造函数:初始化列表,如果first和second是成员对象或基本类型变量(等于不初始化),都用无参构造函数初始化,
	pair(const _T1 &__a, const _T2 &__b)
	:first(__a), second(__b){}
	//②a:初始化first,b:初始化second
	template<class _U1, class _U2>
	pair(const pair<_U1, _U2> & __p)
	:first(__p.first), second(__p.second){}
	//③函数模板(构造函数),用另一个pair对象初始化
};
  • ③:实例
pair<int, int> p(pair<double, double>(5.5, 4.6));
//p.first = 5, p.second = 4
  • map / multimap 容器里放着的都是pair模板类实例化出的对象,且按first从小到大排序 见 2.4
  • set / multiset 中一些成员函数的返回值是pair对象 见 2.3

2.3 set和multiset

2.3.1 multiset

template<class Key, class Pred = less<Key>, 
		class A = allocator<Key> > 
class multiset{
	...
};
  • class Key: multiset中元素的类型

  • class Pred:元素比大小的规则(multiset运行时,若比较x、y大小,回生成一个Pred类型的变量,假定为op(函数对象、函数指针…),若表达式op(x, y)返回值true,则x<y)

  • class Pred = less<Key>: Pred的缺省类型为:less<Key>(less 就是靠<比较大小) 见:实例1

  • class A = allocator<Key>: 不重要,可以不给出

  • 实例1:less模板

template<class T>
struct less:public binary_function<T, T, bool>{
	bool operator () (const T& x, const T& y){
		return x < y;
	}
	const;
};
  • multiset的成员函数:
函数功能
iterator find(const T& val);在容器中查找值为val的元素,返回其迭代器。若未找到,返回end()
iterator insert(const T& val);将val插入到容器中并返回其迭代器
void insert(iterator first, iterator last);将区间[first, last)插入容器
int count(cosnt T& val);统计有多少元素与val"相等"(不小于也不大于)
iterator lower_bound(const T& val);查找一个最大的位置it,是的[begin(), it)中所有的元素都比val小
iterator upper_bound(cosnt T& val);查找一个最小的位置it,是的[it, end())中所有的元素都比val大
pair<iterator, iterator> equal_range(const T& val);同时求得lower_bound和upper_bound
iterator erase(iterator it);删除it指向的元素,返回其后面的元素的迭代器(Vs2010中)
  • 实例1
#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的对象能用 < 比较,即使当重载了 <

  • 实例2
#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;
	//输出: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) ";	cout << *pp <<endl;
	//输出: 5) 33
	MSET2 m2;	//m2里的元素按n的个数从小到大排
	m2.insert(a, a + SIZE);
	cout << "6) ";	Print(m2.begin(), m2.end());
	//输出:6) 40 22 33 4 8 19
	return 0; 
} 

2.3.2 set

没有重复元素(既不小于,也不大于)

template<class Key, class Pred = less<Key>, class A = allocator<Key> >
class 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);
	pair<IT, bool> result;
	result = st.insert(5);
	if(result.second)	
	//插入成功则输出被插入元素 
		cout << *result.first << " inserted" <<endl;
	if(st.insert(5).second)	//再次插入5,判断是否插入成功 
		cout << *result.first <<endl;
	else
		cout << *result.first << " already exists" <<endl;
	pair<IT, IT> bounds = st.equal_range(4);	//同时求lower/upper_bound
	cout << *bounds.first << "," << *bounds.second;
	return 0;
} 

TIPS:插入set已有元素时,忽略插入

2.4 map和multimap

2.4.1 multimap

template<class Key, class T, class Pred = less<Key>, 
		class A = allocator<T> >
class multimap{
	...
	typedef pair<const Key, T> value_type;
	...
};
//Key代表关键字的类型(first), T:值(second) 

TIPS: multimap允许有多个元素的关键字相同。元素按照first成员变量从小到大排序,缺省情况下用 less<Key>定义关键字的"小于"关系

  • 实例
#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));
	//typedef pair<const Key, T> value_type;
	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++)
	//遍历multimap:按first从小到大排序 
		cout << "(" << i->first << "," << i->second << ")" <<"," ;
} 
  • 例题:学生成绩录入和查询系统
  • 输入:
Add name id score
//name是字符串,中间没有空格; id为int; score为int; id不会重复,name和score可能重复
Query score
//查找分数比score低的最高分获得者的信息,多个满足条件,输出学好最大的,找不到输出“nobody”
#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;
//first:int=score; second:CStudent::CInfo内部类使用方法
//缺省情况按less<int>,即score从小到大排序 

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));
			//value_type:指MAP_STD中元素的类型 
		}
		else if(cmd == "Query"){
			int score;
			cin >> score;
			MAP_STD::iterator p = mp.lower_bound(score);
			if(p != mp.begin()){
			//若能找到 
				--p;
				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;
					} 
				}
				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; 
		}
	} 
	return 0;
} 

TIPS:

mp.insert(MAP_STD::value_type(st.score, st.info));
//等价于:mp.insert(make_pair(st.score, st.info));

2.4.2 map

map中的元素都是pair,且关键字first各不相同

template<class Key, class T, class Pred = less<Key>, 
		class A = allocator<T> >
class map{
	...
	typedef pair<const Key, T> value_type;
	...
};
  • map的[]成员函数:
    若pairs为map模板类的对象,pairs[key]返回对关键字等于key的元素的值(second)的引用。若没有关键字为key的元素,则会往pairs里插入一个关键字为key的元素,其值用无参构造函数初始化,并返回其值的引用
  • 实例:[]
map<int, double> pairs;
pairs[50] = 5;
//会将pairs中关键字为50的元素修改为5,若不存在关键字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;
	//map无重复元素,故第二个15插入不成功 
	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 << ",";	 
}

三. 容器适配器: stack、queue、priority_queue

3.1 stack(栈)

后进先出
内部:可用vector, list, deque实现(用list实现性能差),缺省情况下,用deque实现

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

3.1.1 操作一波

  1. stack上可以进行以下操作:
函数功能
push插入元素
pop弹出元素
top返回栈顶元素的引用
empty()判空
size()获得大小(元素个数)

3.2 queue(队列)

先进先出
和stack类似,可以用list和deque实现,缺省用deque

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

3.2.1 操作一波

函数功能
push插入元素
pop弹出元素
frong()访问队首元素
back()访问队尾元素
empty()判空
size()获得大小(元素个数)

3.3 priority_queue(队列)

和queue类似,可以用vector和deque实现,缺省用vector实现
priority_queue通常用堆排序技术实现,保证最大的元素总是在最前面。即执行pop操作时,删除的时最大的元素;执行top操作时,返回的是最大元素的引用。
默认的元素比较器是less<T>

template<class T, class Container = vector<T>,
		class Compare = less<T> >
class priority_queue;

3.3.1 操作一波

  1. push、pop 时间复杂度 O(log n)
  2. top() 时间复杂 O(1)
函数功能
push插入元素
pop弹出元素
top访问队首元素(堆顶)
empty()判空
size()获得大小(元素个数)

3.3.2 优先级的设置

1) 基本类型:缺省为大的数字优先级高
以下俩种定义等价:

priority_queue<int> pq;
priority_queue<int, vector<int>, less<int> > pq;
//vector是定义堆实现的容器

2)结构体:重载(overload)运算符<

  • p1:
struct ClassName{
	int x;
	friend bool operator < (ClassName c1, ClassName c2){
		return c1 < c2;
	} 
};
priority_queue<ClassName> pq;
  • p2:
struct cmp{
	bool operator () (ClassName c1, ClassName c2){
		return c1.x < c2.x;
	}
};
priority_queue<ClassName, vector<ClassName>, cmp> pq;

3.3.3 实例

#include <queue>
#include <iostream>
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;
	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 
	return 0; 
} 

3.4 杂七杂八

  1. 容器适配器的元素个数的获得:
    stack、queue、priority_queue都有:
函数功能
empty()判断适配器是否为空
size()返回适配器中元素的个数
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值