容器简介
STL标准容器类简介
标准容器类 说明
顺序性容器
vector 相当与数组,从后面快速的插入与删除,直接访问任何元素
deque 双队列,从前面或后面快速的插入与删除,直接访问任何元素
list 双链表,从任何地方快速插入与删除
关联容器
set 快速查找,不允许重复值
multiset 快速查找,允许重复值
map 一对一映射,基于关键字快速查找,不允许重复值
multimap 一对多映射,基于关键字快速查找,允许重复值
容器适配器
stack 后进先出
queue 先进先出
priority_queue 最高优先级元素总是第一个出列
所有标准库共有函数
默认构造函数 提供容器默认初始化的构造函数。
复制构造函数 将容器初始化为现有同类容器副本的构造函数
析构函数 不再需要容器时进行内存整理的析构函数
empty 容器中没有元素时返回true,否则返回false
max_size 返回容器中最大元素个数
size 返回容器中当前元素个数
operator= 将一个容器赋给另一个容器
operator< 如果第一个容器小于第二个容器,返回true,否则返回false,
operator<= 如果第一个容器小于或等于第二个容器,返回true,否则返回false
operator> 如果第一个容器大于第二个容器,返回true,否则返回false
operator>= 如果第一个容器大于或等于第二个容器,返回true,否则返回false
operator== 如果第一个容器等于第二个容器,返回true,否则返回false
operator!= 如果第一个容器不等于第二个容器,返回true,否则返回false
swap 交换两个容器的元素
其中operator>,operator>=,operator<,operator<=,operator==,operator!=均不适用于priority_queue
顺序容器和关联容器共有函数
begin 该函数两个版本返回iterator或const_iterator,引用容器第一个元素
end 该函数两个版本返回iterator或const_iterator,引用容器最后一个元素后面一位
rbegin 该函数两个版本返回reverse_iterator或const_reverse_iterator,引用容器最后一个元素
rend 该函数两个版本返回reverse_iterator或const_reverse_iterator,引用容器第一个元素前面一位
erase 从容器中清除一个或几个元素
clear 清除容器中所有元素
下表显示了顺序容器和关联容器中常用的typedef,这些typedef常用于变量、参数和函数返回值的一般性声明。
value_type 容器中存放元素的类型
reference 容器中存放元素类型的引用
const_reference 容器中存放元素类型的常量引用,这种引用只能读取容器中的元素和进行const操作
pointer 容器中存放元素类型的指针
iterator 指向容器中存放元素类型的迭代器
const_iterator 指向容器中存放元素类型的常量迭代器,只能读取容器中的元素
reverse_iterator 指向容器中存放元素类型的逆向迭代器,这种迭代器在容器中逆向迭代
const_reverse_iterator 指向容器中存放元素类型的逆向迭代器,只能读取容器中的元素
difference_type 引用相同容器的两个迭代器相减结果的类型(list和关联容器没有定义operator-)
size_type 用于计算容器中项目数和检索顺序容器的类型(不能对list检索)
容器的比较
vector (连续的空间存储,可以使用[ ]操作符)快速的访问随机的元素,快速的在末尾插入元素,但是在序列中间岁间的插入,删除元素要慢,而且如果一开始分配的空间不够
的话,有一个重新分 配更大空间,然后拷贝的性能开销
deque (小片的连续,小片间用链表相连,实际上就是一个每小片指针的数组,因为知道类型,所以还是可以使用【】,只是速度没有vector快)快速的访问随机的元素,快速
的在开始和末尾插入元素,随机的插入,删除元素要慢,空间的重新分配要比vector快
list (每个元素间用链表相连)访问随机元素不如vector快,随机的插入元素比vector快,对每个元素分配空间,所以不存在空间不够,重新分配的情况
set 内部元素唯一,用一棵平衡树结构来存储,因此遍历的时候就排序了,查找也比较快的哦。
map 一对一的映射的结合,key不能重复。
1、vector
连续存储结构,每个元素是在内存上是连续的;
支持高效的随机访问和在尾端插入/删除操作,但其他位置的插入/删除操作效率低下;
2、deque
连续存储结构,即其每个元素在内存上也是连续的,类似于vector,不同之处在于,deque提供了两级数组结构,第一级完全类似于vector,代表实际容器;另一级维护容器的首位地址。
这样,deque除了具有vector的所有功能外,还支持高效的首端插入/删除操作。
3、list
非连续存储结构,具有双链表结构,每个元素维护一对前向和后向指针,因此支持前向/后向遍历。
支持高效的随机插入/删除操作,但随机访问效率低下,且由于需要额外维护指针,开销也比较大。
list支持push_front(),push_back(),pop_front(),pop_back()
list不支持'[]'和at(),因为它不是连续存放的.
标准模板库里比大小都用<,比等于用==
4、vector V.S. list V.S. deque:
a、若需要随机访问操作,则选择vector;
b、若已经知道需要存储元素的数目, 则选择vector;
c、若需要随机插入/删除(不仅仅在两端),则选择list
d、只有需要在首端进行插入/删除操作的时候,才选择deque,否则都选择vector。
e、若既需要随机插入/删除,又需要随机访问,则需要在vector与list间做个折中。
f、当要存储的是大型负责类对象时,list要优于vector;当然这时候也可以用vector来存储指向对象的指针,同样会取得较高的效率,但是指针的维护非常容易出错,因此不推荐使用。
5、capacity V.S size
a、capacity是容器需要增长之前,能够盛的元素总数;只有连续存储的容器才有capacity的概念(例如vector,deque,string),list不需要capacity。
b、size是容器当前存储的元素的数目。
c、vector默认的容量初始值,以及增长规则是依赖于编译器的。
6、用vector存储自定义类对象时,自定义类对象须满足:
a、有可供调用的无参构造函数(默认的或自定义的);
b、有可用的拷贝赋值函数(默认的或自定义的)
7、迭代器iterator
a、vector与deque的迭代器支持算术运算,list的迭代器只能进行++/--操作,不支持普通的算术运算。
8. pair类型
pair<T1, T2> p1; | 创建一个空的pair对象,它的两个元素分别是T1和T2类型,采用值初始化 |
pair<T1, T2> p1(v1, v2); |
创建一个pair对象,它的两个元素分别是T1和T2类型,其中first成员初始化为v1,second成员初始化为v2 |
make_pair(v1, v2) | 以v1和v2值创建一个新的pair对象,其元素类型分别是v1和v2的类型 |
p1 < p2 | 字典次序:如果p1.first<p2.first或者!(p2.first < p1.first)&& p1.second<p2.second,则返回true |
p1 == p2 | 如果两个pair对象的first和second成员依次相等,则这两个对象相等。 |
p.first | 返回p中名为first的(公有)数据成员 |
p.second | 返回p中名为second的(公有)数据成员 |
map类型
map<K, V>::key_type | 在map容器内,用做索引的键的类型 |
map<K, V>::mapped_type | 在map容器中,键所关联的值的类型 |
map<K, V>::value_type | map的值类型:一个pair类型,它的first元素具有 const map<K, V>::key_type类型,而second元素 则为map<K, V>::mapped_type类型 |
map<K, V> m; | 创建一个名为m的空map对象,其键和值的类型分别为K和V |
map<K, V> m(m2); | 创建m2的副本m,m与m2必须有相同的键类型和值类型 |
map<k, V> m(b, e); | 创建map类型的对象m,存储迭代器b和e标记的范围内所有元素的副本。元素的类型必须能转换为pair<const k, v> |
A::reference operator[](const Key& key); |
[]操作符返回键key所关联的值的引用;如果该键key不存在,则向map对象添加一个新的元素,元素的键为key,所关联的值采用值初始化。(要特别留意这个副作用) |
例如:
|
m.insert(e) | e是一个用在m上的value_type类型的值,如果键(e.first)不在m中,则插入e到m中;如果键已经在m中存在,则保持m不变。 该函数返回一个pair类型对象,如果发生了插入动作,则返回pair(it, true);否则返回pair(it, false)。其中,it是指向键为e.first那个元素的迭代器。 |
m.insert(beg, end) |
beg和end是标记元素范围的迭代器,其中的元素必须为value_type类型的键-值对。对于该范围内的所有元素,如果它的键在m中不存在,则将该键及其关联的值插入到m。返回void类型。 |
m.insert(iter, e) | insert(e),并以iter为起点搜索新元素的位置。返回一个迭代器,指向m中键为e.first的元素。 |
m.count(k) | 返回m中k的出现次数(0或1) |
m.find(k) | 如果容器中存在键为k的元素,则返回指向该元素的迭代器。 如果不存在,则返回end()值。 |
m.erase(k) | 删除m中键为k的元素,返回size_type类型的值,表示删除的元素个数(0或1) |
m.erase(p) | 从m中删除迭代器p所指向的元素。p必须指向m中确实存在的元素,而且不能等于e.end()。返回void类型 |
m.erase(b, e) | 从m中删除[b, e)范围内的元素,返回void类型 |
set类型
multimap和multiset类型
m.lower_bound(k) | 返回一个迭代器,指向键不小于k的第一个元素 |
m.upper_bound(k) | 返回一个迭代器,指向键大于k的第一个元素 |
m.equal_range(k) | 返回一个迭代器的pair对象;它的first成员等价于 m.lower_bound(k),而second成员则等价于 m.upper_bound(k) |
//vector例子
#include <iostream>
using namespace std;
#include <vector>
int main()
{
vector<int> vi;
cout << "Input scores,end by -1:";
int s;
int m=0;
for(;;){
cin >> s;
if(s==-1) break;
vi.push_back(s);
if(s>m)
m = s;
}
int inc = 100-m;
for(int i=0; i<vi.size(); i++)
vi[i] += inc;
for(int i=0; i<vi.size(); i++)
cout << vi[i] << ' ';
cout << endl;
try{
cout << "vi[1000]=" << vi[1000] << endl;
cout << "vi.at(1000)=" << vi.at(1000) << endl;
}catch(exception& e){
cout << e.what() << endl;
}
}
存取首尾元素
front()与back()操作,取后一个和最前一个元素,注意其返回是引用,其而是左值(l_value),因此可以赋值. 做类似于vecobj.front() = 3;的操作,但要保证front空间有效,否则形为无法预测。
使用assign
assign可以改变大小和初值,大小是随意的,不受开始时大小的限制,如果设置为0,则清空。
assign(5,0)把vector改为5个大小,并用0添充
assign(iax+3,iax+5); 从数组第4到5个填充,注意左闭右开,即可取到iax[3]与iax[4]
使用insert
insert(it, x),在it前插入一个元素x
insert(it,first,last),在it前插入一个序列[first,last)左闭右开
使用erase
erase(it)删除在it处的元素,返回值为下一元素。如果intVec.erase(intVec.end());并不会报错,如果删除一个序列[first,last),使用erase(first,last)
//list.cc
#include <iostream>
using namespace std;
#include <list>
int main()
{
int cpp[5] = {3,5,6,8,9};
int java[8] = {1,2,3,4,5,6,7,8};
int Unix[4] = {3,4,5,6};
list<int> li;
li.insert(li.begin(),cpp,cpp+5);
li.insert(li.begin(),java,java+8);
li.insert(li.begin(),unix,unix+4);
li.sort();//排序
li.unique();//删除相邻的重复的元素,只留一份
list<int>::iterator it = li.begin();
while(it!=li.end())
cout << *it++ << ' ';
cout << endl;
}
二、操作
1.resize & clear
使用resize(n)改变大小,使用resize(n, val)如果需要用T(val) 来填满空闲值。
2.front ()& back()
如果listObj非常量对象,返回是一个左值函数
3.插入操作
insert(iterator it , val)
insert(iterator it, first, last)
insert(iteratot it, n, x)//插入n个x
4.移除 [按值删]
remove(x); //vector.erase(integrator it)
//map.cc
#include <iostream>
#include <map>
using namespace std;
#include <string>
int main()
{
map<int, string> m;
m.insert(make_pair(1001,"李明"));
m.insert(make_pair(1002,"王国"));
m.insert(make_pair(1005,"失小"));
m[1006] = "刘华";
m.insert(make_pair(1001,"娜娜"));
map::iterator it;
it = m.begin();
while(it!=it.end()){
cout << it->first << ':' << it->second << endl;
++ it;//会比it++性能高
}
}
对于set,map来说重复的插入被忽略.
//multimap
//一切操作都是对key而言的
//key一定要支持小于运算符,不然是不能进行排序的
#include <iostream>
using namespace std;
#include <map>
#include <string>
int main()
{
typedef multimap<string,string> M;
M mss;
M::iterator ib,ie;
mss.insert(make_pair("a","b"));
mss.insert(make_pair("c","d"));
mss.insert(make_pair("e","f"));
mss.insert(make_pair("c","p"));
mss.insert(make_pair("a","m"));
mss.insert(make_pair("c","d"));
mss.insert(make_pair("a","p"));
ib = mss.begin();
ie = mss.end();
while(ib!=ie){
cout << ib->first <<',' << ib->second << endl;
++ ib;
}//end while
cout << "a count : " << mss.count("a") << endl;
cout << "c count : " << mss.count("c") << endl;
ib = mss.lower_bound("c");
ie = mss.upper_bound("c");
while(ib!=ie){
cout << ib->first <<',' << ib->second << endl;
++ ib;
}//end while
}//end main
//set
//同样的插入同样被忽略
#include <iostream>
using namespace std;
#include <set>
int main()
{
set<int> si;
int userid[5] = {1,3,3,4,5};
for(int i=0;i<5; i++)
si.insert(userid[i]);
set<int>::iterator it;
it = si.begin();
while(it!=si.end())
cout << *it++ << ' ';
cout << endl;
cout << "user 3 : " << (si.find(3)!=si.end()) << endl;
cout << "user 9 : " << (si.find(9)!=si.end()) << endl;
}
//multiset
//用的是平衡二叉树,所以它的查找效率是相当高的.
#include <iostream>
using namespace std;
#include <set>
template<typename Iter>
void show(Iter ib, Iter ie)
{
while(ib!=ie)
cout << *ib++ << ' ';
cout << endl;
}
int main()
{
int a[5] = {5,1,7,5,1};
multiset<int> pids(a,a+5);
show(pids.begin(),pids.end());
pids.insert(7);
pids.insert(7);
pids.insert(7);
pids.erase(pids.find(5));
show(pids.begin(),pids.end());
cout << "end process 7..." << endl;
pids.erase(7);
show(pids.begin(),pids.end());
}//end main