c++ primer 9 顺序容器
定义:
1 #include <vector> 2 #include <list> 3 #include <deque> 4 5 vector<int> svec; 6 list<int> ilist; 7 deque<int> items;
初始化:
1. 将一个容器初始化为另一个容器的副本
容器类型,元素类型必须相同
1 vector<int> a; 2 vector<double> d(a); 3 4 list<double> b; 5 vector<double> d(b); 6 7 vector<double> c; 8 vector<double> d(c);
只有最后一个是合法的
2. 初始化一段元素的副本
不能将一种容器内的元素赋值给另一个容器,但允许通过传递一对迭代器间接实现该功能。使用迭代器不要求容器类型相同,也不要求容器内元素类型相同,只要它们互相兼容
可以通过一个容器的迭代器初始化另一个容器,可以刻通过内置数组中的指针初始化容器(指针就是迭代器 )
1 int main() 2 { 3 char *num[] = {"one","two","three","fore","five"}; //用指针的方式初始化容器 4 int num_size = sizeof(num)/sizeof(char *); 5 vector<string> vec(num,num+num_size); 6 for(int i = 0 ;i < num_size;i++) 7 cout<<vec[i]<<endl; 8 9 deque<string> deq(vec.begin(),vec.end()); //用迭代器初始化容器 10 for(int i = 0 ;i < num_size;i++) 11 cout<<deq[i]<<endl; 12 13 }
3. 分配和初始化指定数目的元素(只用于顺序容器)
1 const vector<int>::size_type a_size = 10; 2 vector<int> a(a_size);
初始化10个0(默认是0),size_type类型保存容器元素长度。
容器元素类型的约束
支持赋值运算和可以复制
容器的容器: eg:定义一个list对象来存储deque对象,该deque对象存放int型元素:list< deque<int> > lst;
注意两个相邻的< <之前必须有空格否则会被认为左移操作符
迭代器和迭代器范围
所有容器的迭代器都支持以解引用运算从容器中读入一个元素
所有容器迭代器都支持 * -> ++ -- == !=
vector,deque迭代可以进行算术运算和关系运算
list的迭代器不支持算术运算和关系运算(除了== !=)
9.9 逆序输出list:
1 int main() 2 { 3 char *num[] = {"one","two","three","fore","five"}; 4 int num_size = sizeof(num)/sizeof(char *); 5 list<string> lst(num,num+num_size); 6 list<string>::iterator ite1 = lst.begin(),ite2 = lst.end(); 7 while(ite2 != ite1) 8 cout<<*(--ite2)<<endl; 9 }
迭代器的范围的要求:
假设[first,last)
1. 指向同一容器中的元素或超出末端的下一个位置(所以用数组a初始化一个迭代器是(a,a+a_size))
2. 如果这两个迭代器不想等,则对first反复做自增运算能达到last,就是last不能位于first之前
迭代器范围是左闭右开的意义:
1. first与last相等时迭代器为空
2. 不相等时迭代器范围内至少有一个元素
9.12 写一个形参是一对迭代器和int型整数,查找整数返回bool
1 bool find_num(vector<int>::iterator ite1,vector<int>::iterator ite2,int n); 2 int main() 3 { 4 int num[] = {1,2,3,4,5}; 5 vector<int> vec(num,num+5); 6 if(find_num(vec.begin(),vec.end(),5)) 7 cout<<"find"<<endl; 8 else 9 cout<<"can't find"; 10 return 0; 11 } 12 13 bool find_num(vector<int>::iterator ite1,vector<int>::iterator ite2,int n) 14 { 15 while(ite1 != ite2) 16 { 17 if(*(ite1++) == n) 18 return true; 19 } 20 return false; 21 }
迭代器失效
向容器中增加或删除元素会使迭代器失效,建议用end操作符返回的迭代器
1 vector<int>::iterator first = vec.begin(),last = vec.end(); 2 while(first != last) //不让其失效把last替换vec.end() 3 { 4 first = v.insert(first,7); 5 ++first; 6 }
顺序容器的操作 p272表格已列出
容器定义类型别名
size_type 存储容器长度
iterator 此容器的迭代器类型
value_type 元素类型,程序无须直接知道容器元素的真正类型就可以使用它
reference 该容器元素的引用,value_type&的同义词
c.begin() 返回一个迭代器,指向c容器第一个元素
c.end() 返回一个迭代器,指向c容器的最后一个元素
c.push_back(t) 在容器c的尾部添加值为t的元素,返回void类型
c.push_front(t) 在容器c的前端添加值为t的元素,返回void类型(仅用于list和deque)
c.insert(p,t) 在迭代器p前插入元素t
c.insert(p,n,t) 在迭代器p前插入n个元素t
c.insert(p,b,e) 在迭代器p前插入b,e之间的元素
容器的比较
比较的容器必须有相同的容器类型,而且其元素类型也必须相同
容器的比较实际上就是元素的比较p277页例子
容器大小的操作
c.size() 返回容器c中的元素个数
c.empty() 检查容器是否为空,返回bool
c.resize(n) 调整容器c的大小,当前容器大小大于新的长度,则容器后的元素就都删除,小于就添加新元素,可用(n,t)指定
访问元素
front和back成员,返回容器内第一个或最后一个元素的引用
.at()方式比用[]下标操作符的好的地方在于可以检查越界
注意list容器不能通过[]下标访问,也没有.at()方法,只能通过迭代器访问
9.24 三种方式获取容器第一个元素
1 int main() 2 { 3 vector<int> vec; 4 cout<<"Enter some intergers for vector(Ctrl + z to end)"<<endl; 5 int num; 6 while(cin>>num) 7 vec.push_back(num); 8 if(vec.empty()) //注意检查是否为空 9 cout<<"No element"<<endl; 10 else 11 cout<<vec.at(0)<<endl; //检查越界 12 cout<<*vec.begin()<<endl; 13 cout<<vec.front()<<endl; 14 return 0; 15 }
删除元素
c.erase(p) 删除迭代器p指向的元素,返回一个迭代器(指向被删除元素后面的元素)
c.erase(b,e)
c.clear() 删除容器内所有元素,返回void
c.pop_back() 删除容器c的最后一个元素,返回void
c.pop_front() 删除容器c的第一个元素,返回void(list,deque适用)
注意:pop_front和pop_back函数返回值不是被删除的元素而是void,要获取删除元素的值,则必须在删除元素之间调用front或back函数
练习.pop_back()和erase()删除其中一个元素,find方法在#include<algorithm>
1 #include <iostream> 2 using namespace std; 3 #include <vector> 4 #include <algorithm> 5 6 int main() 7 { 8 int num[] = {1,2,3,4,5}; 9 vector<int> vec(num,num+5); 10 cout<<vec.back()<<endl; 11 vec.pop_back(); //vector没有pop_front方法 12 cout<<vec.back()<<endl; 13 14 vector<int>::iterator ite; 15 ite = find(vec.begin(),vec.end(),3); 16 cout<<*ite<<endl; 17 vec.erase(ite); 18 19 return 0; 20 }
9.26 删除迭代器中偶数元素
int main() { int ia[] = {0,1,1,2,3,5,8,13,21,55,89}; int ia_size = sizeof(ia)/sizeof(int); vector<int> vec(ia,ia+ia_size); vector<int>::iterator vite = vec.begin(); while(vite != vec.end()) { if((*vite)%2 == 0) vite = vec.erase(vite); else ++vite; } vite = vec.begin(); while(vite != vec.end()) cout<<*vite++<<" "; return 0; }
赋值与swap
c1 = c2 容器类型元素类型必须相同
c1.swap(c2) 也要求容器类型和元素类型都要相同,而且使用swap交换元素后,不会使原本指向这两个容器中的元素的迭代器失效,只不过他们都变成指向另一个迭代器中的相应位置了
c.assign(b,e) b,e是一段迭代器,容器类型可以不同
vector容器自增长
c.capacity() 输出容器的容量
c.reserve(50) 预分配容器大小为50
容器选择:通常来说,除非找到选择使用其他容器更好的理由,否则vector容器都是最佳选择
string类型
可将string类型看作字符容器,和vector的操作类似,P289
容器适配器
stack 栈
deque 队列
priority_queue 有优先级管理的队列
stack可以和任意顺序容器关联,queue只能建立在list容器上(因为需要push_front操作),priority_queue建立在vector或者deque容器上(因为需要随机访问)