Cpp.P笔记02

顺序容器(sequential container):容器内的元素根据位置来存储和访问,元素的排列次序与元素值无关

(1)标准库定义了三种顺序容器类型:vector、list、deque

(2)三种容器的差别在于:访问元素的方式,以及添加或删除元素相关操作的运行代价

容器只定义了少量操作,大多数额外操作由算法库提供;所有容器都是类模板


一、容器元素的初始化

  C<T> c;                 创建名为c的空容器

  C<T> c(c2);           创建容器c2的副本c

  C<T> c(b, e);         创建容器c,其元素是迭代器 b 和 e 标识范围内的元素的副本(使用形参为一对迭代器的constructor)

  C<T> c(n, t);          创建容器c,其元素为 n 个 T 类型的 t 值                                                     【只适用于顺序容器】

  C<T> c(n);             创建有 n 个 T 类型元素的容器c,其元素值通过默认构造函数给出           【只适用于顺序容器】

例:sequential container

list<int> ilist;                  					//假设ilist的元素为2,3,6,9,13  
while (cin >> t)  
{  
	if (t=='Q') break;  
	ilist.push_back(t);  
	ilist.push_front(t-1);                           //适用于list和deque容器类型
}  
// insert操作,新元素插入在迭代器指向位置『之前』  
ilist.insert(ilist.begin(), -13);  
ilist.insert(ilist.end(), 13);  
// 下标操作(list容器不支持),以下语句错误  
//  for(list<int>::size_type ix = 0; ix != ilist.size(); ++ix)  
//      cout << ilist[ix] << ',';  
// 迭代器  
for(list<int>::iterator iter = ilist.begin(); iter != ilist.end(); ++iter)  
	cout << *iter << ',';  
cout << endl;  

list<int> ilist_copy(ilist);                         // ilist_copy的元素也为2,3,6,9,13  
list<int> ilist_copy1(ilist.begin(),ilist.end());    // ilist_copy1的元素也为2,3,6,9,13  
list<string> slist1(8, "hi");                        // slist1的元素为hi,hi,hi,hi,hi,hi,hi,hi  
list<string> slist2(9);                              // slist2的元素为,,,,,,,(每个元素都是空字符串)  

list<int> ilist1(8,1);                               // ilist1的元素为1,1,1,1,1,1,1,1  
list<int> ilist2(9);                                 // ilist2的元素为0,0,0,0,0,0,0,0,0(每个元素的默认值为0)  

// 不能直接将一种容器内的元素复制给另一种元素,但是可以通过传递一对迭代器间接实现该功能。  
vector<string> svec(3,"hi");                         // svec的元素为hi,hi,hi,he,he,he  
svec.push_back("he");  
svec.push_back("he");  
svec.push_back("he");  
list<string> slist3(svec.begin(),svec.end());        // slist3的元素也为hi,hi,hi,he,he,he  
vector<string>::iterator mid = svec.begin() + svec.size()/2;  
deque<string> front(svec.begin(),mid);               // front的元素为hi,hi,hi  
deque<string> back(mid,svec.end());                  // back的元素为he,he,he 

二、容器内元素的类型约束

【最低要求】必须满足以下两个条件:

(1)元素类型必须支持赋值运算

(2)元素类型的对象必须可以复制

除了引用类型之外(引用不支持赋值),所有内置或者复合类型都可以用作元素类型。

除了IO库以及auto_ptr类型,所有其他标准库类型都是有效的容器元素类型。


容器的容器:容器本身也满足上述要求,可定义元素是容器类型的容器。

  vector< vector<string> > lines;                 // vector of vector,必须在<和v(>和>)之间使用空格

例:containers of container

vector<string> svec0(3, "hi");
vector<string> svec1(3, "he");
vector<string> svec2(3, "wd");
vector< vector<string> > lines;
lines.push_back(svec0);
lines.push_back(svec1);
lines.push_back(svec2);
for(vector< vector<string> >::iterator iter = lines.begin(); iter != lines.end(); ++iter)
{
	for(vector<string>::iterator iter1 = iter->begin(); iter1 != iter->end(); ++iter1)
		cout << *iter1 << ',';
	cout << endl;
}
cout << endl;
其结果为:

hi,hi,hi,
he,he,he,
wd,wd,wd,

三、迭代器 iterator

使用a pair of iterator(一对迭代器)来标记iterator range(迭代器范围),通常分别指向同一个容器中的两个元素或超出末端的下一位置,用于标记容器中的一段元素范围。

常用迭代器运算:

  *iter                     // 返回迭代器iter所指向元素的引用(iter相当于指针)

  iter->mem                                            // 获取指定元素中名为mem的成员,等效于(*iter).mem

  ++iter  和  iter++                                  // iter值自加,使其指向容器里的下一个元素

  --iter  和  iter--                                      // iter值自减

  iter1 ==  iter2   和   iter1 != iter2          // 比较两个迭代器是否相等(或不等)


vectordeque容器的迭代器还支持(list容器不支持算术运算,也不支持关系运算): 

  iter + n  和  iter - n

       iter += iter2  和  iter -= iter2

       iter1 - iter2

       >   >=   <   <=                                       // 关系运算 

特别地,一些容器操作会修改容器的内在状态移动容器内的元素,这样的操作会使得所有指向被移动元素的迭代器失效,也可能同时使其他迭代器失效。

例如,使用erase函数删除了容器中某个元素,指向这个被删除元素的迭代器就无效了。


四、顺序容器的操作

1. 容器定义的类型:

  size_type                 // 无符号整型   

  iterator和const_iterator            // 迭代器类型,只读迭代器类型 

  reverse_iterator和const_reverse_iterator     // 逆序迭代器类型,只读逆序迭代器类型  

  difference_type                // 存储两个迭代器差值的有符号整型(可为负数)       

  value_type                  // 元素类型      

  reference和const_reference         // 元素的左值类型(value_type&),元素的常量左值类型(const value_type&)      

其中,最后三种类型(value_type, reference, const_reference),无需直接知道容器元素的真正类型就能使用。

  list<string>::iterator iter;

  vector<int>::difference_type cnt;

  vector<string>::value_type str;


2. 添加元素相关操作

在容器中添加元素时,系统是将元素值复制到新容器里,新容器存放的是原始元素的副本

被复制的原始值与新容器中的元素各不相干,即:容器内元素值发生变化时,被复制的原始值不会受到影响。

  list<int> ilist;

  ilist.begin();                    // 返回指向容器的第一个元素的迭代器

  ilist.end();                       // 返回指向容器的最后一个元素下一个位置的迭代器

  ilist.push_back(t);    // 在容器的尾部,添加值为 t 的元素,返回void类型              【例如,      ilist.push_back(2);         此时,ilist为1     】

  ilist.push_front(t);          // 在容器的前端,添加值为 t 的元素, 返回void类型             【例如,      ilist.push_front(1);         此时,ilist为1,2   】

  ilist.insert(p, t);              // 在迭代器 p 所指向元素的前面,添加值为 t 的元素,         【例如,     ilist.insert(ilist.end(), 3);      此时,ilist为1,2,3   】

                                             // 返回指向新添加元素的迭代器

  ilist.insert(p, n, t);          // 在迭代器 p 所指向元素的前面,添加 n 个值为 t 的元素,返回void类型

  ilist.insert(p, b, e);         // 在迭代器 p 所指向元素的前面,插入由迭代器 b 和 e 标记范围内的元素,返回void类型

例:

list<int> ilist;
list<int>::value_type a=11;
ilist.push_back(2);
ilist.push_front(1);
list<int>::iterator iliter = ilist.insert(ilist.end(), 3);                // iliter指向第3个元素(即:第3个位置)
ilist.insert(ilist.end(), a);
ilist.insert(ilist.end(), 3, 8);
for(list<int>::iterator iter = ilist.begin(); iter != ilist.end(); ++iter)
	cout << *iter << ',';
cout << endl;
list<int> ilist_copy(ilist.begin(), iliter);            // 将第3个位置作为end,所以ilist_copy只包含前ilist的2个元素
for(list<int>::iterator iter = ilist_copy.begin(); iter != ilist_copy.end(); ++iter)
	cout << *iter << ',';
cout << endl;

string str[6] = {"stra", "strb", "strc", "strd", "stre", "strf"};
list<string> slist(6, "hi");
for(list<string>::iterator iter = slist.begin(); iter != slist.end(); ++iter)
    cout << *iter << ',';
cout << endl;
slist.insert(slist.end(), str, str+2);                  // 插入数组中的一段元素(str+2表示end,也就是将str+1作为最后一个元素)
for(list<string>::iterator iter = slist.begin(); iter != slist.end(); ++iter)
    cout << *iter << ',';
cout << endl;
slist.insert(slist.end(), str+3, str+5);                // str+3是插入的第一个元素,str+5表示end,也就是str+4是插入的最后一个元素 
for(list<string>::iterator iter = slist.begin(); iter != slist.end(); ++iter)
    cout << *iter << ',';
cout << endl;
结果为:

1,2,3,11,8,8,8,
1,2,
hi,hi,hi,hi,hi,hi,
hi,hi,hi,hi,hi,hi,stra,strb,
hi,hi,hi,hi,hi,hi,stra,strb,strd,stre,

3. 其他操作

(1)容器大小操作

  ilist.size();                                             // 返回容器的元素个数,返回类型为list<int>::size_type

  ilist.max_size();                                    // 返回容器可容纳的最大元素个数

  ilist.empty();                                          // 返回判断容器大小是否为0的布尔值

  ilist.resize(n);                                        // 重新调整容器的长度,使其可以容纳 n 个元素

  ilist.resize(n, t);                                     // 重新调整容器的长度,使其可以容纳 n 个元素,且所有新添加的元素值都为 t 值

例:

list<int> ilist(10,1);
for(list<int>::iterator iter = ilist.begin(); iter != ilist.end(); ++iter)
	cout << *iter << ',';
cout << endl;
ilist.resize(12);                  // 空出来位置的元素值为 默认构造函数提供的初始值
cout << ilist.size() << endl;
for(list<int>::iterator iter = ilist.begin(); iter != ilist.end(); ++iter)
	cout << *iter << ',';
cout << endl;
ilist.resize(15, -1);              // 增加了3个位置的容量,且增加的3个位置的值设置为-1
for(list<int>::iterator iter = ilist.begin(); iter != ilist.end(); ++iter)
	cout << *iter << ',';
cout << endl;
ilist.resize(5);                   // 减少了容器的容量,只保留能够容纳的那部分元素,去掉多余的元素
for(list<int>::iterator iter = ilist.begin(); iter != ilist.end(); ++iter)
	cout << *iter << ',';
cout << endl;
结果为:

1,1,1,1,1,1,1,1,1,1,
12
1,1,1,1,1,1,1,1,1,1,0,0,
1,1,1,1,1,1,1,1,1,1,0,0,-1,-1,-1,
1,1,1,1,1,
(2)访问元素

如果容器非空,容器类型的frontback成员将返回容器内的第一个和最后一个元素的引用。

  ilist.back();            // 返回容器最后一个元素的引用

  ilist.front();                                             // 返回容器第一个元素的引用

  ilist[n];                                                    // 返回下标为 n 的元素的引用【仅适用于vector和deque容器

  ilist.at(n);                                               // 返回下标为 n 的元素的引用【仅适用于vector和deque容器

例:

vector<int> ivec;
for(int i = 1; i<10; i++)
    ivec.push_back(i);
for(vector<int>::iterator iter = ivec.begin(); iter != ivec.end(); ++iter)
    cout << *iter << ',';
cout << endl;
for(vector<int>::size_type n = 0; n != ivec.size(); ++n)
    cout << ivec[n] << ',';
cout << endl;
for(vector<int>::size_type n = 0; n != ivec.size(); ++n)
    cout << ivec.at(n) << ',';
cout << endl;
if (!ivec.empty())
{
    list<int>::reference val = *ivec.begin();
    list<int>::reference val2 = ivec.front();
    cout << "the first element of ivec: " << val << ", " << val2 << endl;

    list<int>::reference last = *--ivec.end();
    list<int>::reference last2 = ivec.back();
    cout << "the last element of ivec: "  << last << ", " << last2 << endl;
}
cout << endl;
输出结果:

1,2,3,4,5,6,7,8,9,                        // 迭代器dereference
1,2,3,4,5,6,7,8,9,                        // ivec[n]
1,2,3,4,5,6,7,8,9,                        // ivec.at(n)
the first element of ivec: 1, 1
the last element of ivec: 9, 9














猜你喜欢

转载自blog.csdn.net/xfijun/article/details/53423096
cpp