C++ Primer 学习笔记_29_STL实践与分析(3) --操作步骤集装箱(下一个)
STL实践与分析
--顺序容器的操作(下)
六、訪问元素
假设容器非空,那么容器类型的front和back成员将返回容器的第一个和最后一个元素的引用。
【与begin和end的对照:】
1)begin和end返回容器类型的迭代器,而不是引用;
2)end返回容器最后一个元素的下一个位置的迭代器,而back返回容器的最后一个元素的引用!
/*
*必须保证该list容器非空!
*假设容器为空,则if语句内的全部操作都是没有定义的! */
if (!iList.empty())
{
list<int>::reference bVal1 = *iList.begin();
list<int>::reference bVal2 = iList.front(); list<int>::reference eVal1 = *--iList.end();
list<int>::reference eVal2 = iList.back(); cout << "Begin:" << endl;
cout << bVal1 << endl;
cout << bVal2 << endl;
cout << endl << "End:" << endl;
cout << eVal1 << endl;
cout << eVal2 << endl;
}
訪问顺序容器内元素的操作 |
|
---|---|
c.back() |
返回容器c的最后一个元素的引用。假设c为空,则该操作没有定义 |
c.front() |
返回容器c的第一个元素的引用。假设c为空,则该操作没有定义 |
c[n] |
返回下标n的元素的引用,假设n<0或n>=c.size(),则该操作没有定义 仅仅适用于vector和deque容器 |
c.at(n) |
返回下标为n的元素的引用,假设下标越界。则该操作没有定义 仅仅适用于vector和deque容器 |
使用下标运算的一个可选方案是使用at成员函数,尽管这个函数的行为和下标运算相似。可是假设程序给出的下标无效,at函数会抛出out_of_range异常。
vector<string> strVec; cout << strVec[0] << endl; //run-time error
cout << strVec.at(0) << endl; //throw out_of_range
//P280 习题9.24
int main()
{
vector<string> strVec;
strVec.push_back("o(∩∩)o...");
if (!strVec.empty())
{
cout << strVec.front() << endl;
cout << *strVec.begin() << endl;
string tmp = strVec.at(0);
cout << tmp << endl;
tmp = strVec[0];
cout << tmp << endl;
}
}
七、删除元素
删除顺序容器内元素的操作 |
|
---|---|
c.erase(p) |
删除迭代器p所指向的元素 返回一个迭代器,它指向被删除元素后面的元素。 假设p指向容器内的最后一个元素,则返回的迭代器指向容器的超出末端的下一位置。假设p本身就是指向超出末端的下一位置的迭代器,则该函数没有定义 |
c.erase(b,e) |
删除迭代器b和e所标记的范围内全部的元素 返回一个迭代器,它指向被删除元素段后面的元素。假设e本身就是指向超出末端的下一位置的迭代器,则返回的迭代器也指向容器的超出末端的下一位置 |
c.clear() |
删除容器c内的全部元素。返回void |
c.pop_back() |
删除容器c的最后一个元素。返回void。 假设c为空容器, |
c.pop_front() |
删除容器c的第一个元素。返回void。假设c为空容器,则该函数没有定义 仅仅适用于list或deque容器 |
1、删除第一个/最后一个元素
pop_front操作通常与front操作配套使用。实现以栈的方式处理容器:
while (!iDeq.empty())
{
proccess(iDeq.front());
iDeq.pop_front();
}
【注意:】
pop_front和
pop_back函数的返回值并非删除的元素值,而是void。
要获取删除的元素值,则必须在删除元素之前调用front或
back函数。
2、删除容器内的一个/一段元素
erase的两种形式都返回一个迭代器,它指向被删除元素或元素段后面的元素。
也就是说,假设元素j恰好紧跟在元素i后面,则将元素i从容器中删除后,删除操作返回指向j的迭代器。
如同其它操作一样,erase操作也不会检查它的參数。程序猿必须确保用作參数的迭代器或迭代器范围是有效的。因此。在删除元素之前。必须确保迭代器不是end迭代器,假设恰巧是end迭代器,则erase的操作没有定义。
void printVec(const vector<string> &strVec)
{
for (vector<string>::const_iterator iter = strVec.begin(); iter != strVec.end(); ++iter)
{
cout << *iter << endl;
}
}
int main()
{
// freopen("input","r",stdin);
vector<string> strVec;
string val;
while (cin >> val)
{
strVec.push_back(val);
}
printVec(strVec); string searchVal("Quasimodo");
vector<string>::iterator iter = find(strVec.begin(),strVec.end(),searchVal); if (iter != strVec.end())
{
strVec.erase(iter);
}
printVec(strVec);
}
3、删除容器内的全部元素
strVec.clear();
strVec.erase(strVec.begin(),strVec.end());
同一时候,erase函数的迭代器版本号也提供了删除部分元素的功能:
string searchVal("Quasimodo");
vector<string>::iterator iter = find(strVec.begin(),strVec.end(),searchVal);
strVec.erase(strVec.begin(),iter); //不会包括iter指向的元素
printVec(strVec);
假设删除时,两个迭代器指向的元素是同一个元素。则不会删除不论什么元素。假设两个迭代器指向的元素有一个或两个不存在。则会发生执行时错误:
strVec.erase(strVec.begin(),strVec.begin());
printVec(strVec); strVec.erase(strVec.begin(),strVec.end()+1);
printVec(strVec);
【小心地雷o(∩∩)o...,P282】
erase、pop_front和
pop_back函数使指向被删除元素的全部迭代器失效。对于vector容器,指向删除点后面的元素的迭代器通常也会失效。而对于deque容器,假设删除时不包括第一个元素或最后一个元素,那么该deque容器相关的全部迭代器都会失效。
//P282 习题9.26
void printVecInt(const vector<int> &strVec)
{
for (vector<int>::const_iterator iter = strVec.begin(); iter != strVec.end(); ++iter)
{
cout << *iter << '\t';
}
cout << endl;
} void printlistInt(const list<int> &strVec)
{
for (list<int>::const_iterator iter = strVec.begin(); iter != strVec.end(); ++iter)
{
cout << *iter << '\t';
}
cout << endl;
} int main()
{
int ia[] = {0,1,1,2,3,5,8,13,21,55,89};
vector<int> iVec(ia,ia+sizeof(ia)/sizeof(*ia));
list<int> iList(ia,ia+sizeof(ia)/sizeof(*ia));
// printlistInt(iList);
// printVecInt(iVec); for (vector<int>::iterator iter = iVec.begin(); iter != iVec.end(); ++iter)
{
if (!(*iter % 2))
{
iter = iVec.erase(iter);
-- iter;
}
}
printVecInt(iVec); for (list<int>::iterator iter = iList.begin(); iter != iList.end(); ++iter)
{
if (*iter % 2)
{
iter = iList.erase(iter);
-- iter;
}
}
printlistInt(iList);
}
//习题9.27
int main()
{
// freopen("input","r",stdin);
list<string> strList;
string val; while (cin >> val)
{
strList.push_back(val);
} string searchVal("dream");
for (list<string>::iterator iter = strList.begin(); iter != strList.end(); ++iter)
{
if (*iter == searchVal)
{
strList.erase(iter);
--iter;
}
}
for (list<string>::iterator iter = strList.begin(); iter != strList.end(); ++iter)
{
cout << *iter << '\t';
}
cout << endl;
}
八、赋值与swap
顺序容器的赋值与swap操作 |
|
---|---|
c1= c2 |
删除容器c1的全部元素,然后将c2的元素复制给c1。 c1和c2的类型(包含容器类型和元素类型)必须同样 |
c.assign(b,e) |
又一次设置c的元素:将迭代器b和e标记的范围内全部的元素拷贝到c中。 b和e必须不是指向c中元素的迭代器 |
c.assign(n,t) |
将容器c又一次设置为存储n个值为t的元素 |
c1.swap(c2) |
交换内容:调用完该函数后,c1中存放的是c2原来的元素,c2中存放的则是c1原来的元素。 c1和c2的类型必须同样。 该函数的运行速度通常要比将c2拷贝到c1的操作快 |
与赋值相关的操作符都作用于整个容器。除了swap外,其它操作都能够通过erase和insert来替代。
赋值操作符首先删除其左操作数容器的全部元素,然后将右操作数容器的全部元素插入到左边容器中:
vec1 = vec2;
//等效于
vec1.erase(vec1.begin(),vec1.end());
vec1.insert(vec1.begin(),vec2.begin(),vec2.end());
虽然赋值前两个容器的长度可能不相等。可是赋值后两个容器的长度都等于右边容器的长度!
【小心地雷:】
赋值和assign操作使左操作容器的全部迭代器失效,swap操作则不会使迭代器失效。完毕swap操作后,虽然被交换的元素已经存放在还有一容器中,但迭代器仍然指向同样的元素。
1、使用assign
1)带有一对迭代器參数的assign操作同意我们将一个容器的元素赋给还有一个不同类型的容器。
可是两种容器类型与元素类型必须相互兼容!
sList.assign(sVec.begin(),sVec.end());
2)assign运算的第二个版本号须要一个整型数值和一个元素值做參数,它将容器重置为存储指定数量的元素,而且每一个元素的值都为指定值:
sList.assign(10,"o(∩∩)o...");
2、使用swap操作以节省删除元素的成本
swap操作实现交换两个容器内全部元素的功能。要交换的容器的类型必须匹配:操作数必须是同样类型的容器,并且所存储的元素类型也必须同样。
调用了swap函数后,右操作数原来存储的元素被存放在左操作数中,反之亦然。
void printListStr(const list<string> &sList)
{
for (list<string>::const_iterator iter = sList.begin(); iter != sList.end(); ++iter)
{
cout << *iter << endl;
}
} int main()
{
list<string> sList1(3,"o(∩∩)o...");
list<string> sList2(4,"(*^__^*)"); cout << "sList1:" << endl;
printListStr(sList1);
cout << "sList2:" << endl;
printListStr(sList2); sList1.swap(sList2);
cout << "sList1:" << endl;
printListStr(sList1);
cout << "sList2:" << endl;
printListStr(sList2);
}
关于swap的一个重要问题在于:该操作不会删除或插入不论什么元素,并且保证在常量时间内实现交换。
因为容器内没有移动不论什么元素,因此迭代器不会失效。
没有移动元素这个事实意味着迭代器不会失效。它们指向同一元素,就像没作swap运算之前一样。尽管,在swap运算后,这些元素已经被存储在不同的容器之中了。比如,在做
swap运算之前,有一个迭代器iter指向
svec1[3]字符串;实现swap运算后,该迭代器则指向svec2[3]字符串(这是同一个字符串,仅仅是存储在不同的容器之中而已)。
vector<string> sVec1(4,"o(∩∩)o...");
vector<string> sVec2(3,"(*^__^*)"); vector<string>::iterator iter = sVec1.end() - 1;
cout << *iter << endl;
sVec1.swap(sVec2);
cout << *iter << endl;
//P284 习题9.28
void printListStr(const list<string> &sList)
{
for (list<string>::const_iterator iter = sList.begin(); iter != sList.end(); ++iter)
{
cout << *iter << endl;
}
}
版权声明:本文博主原创文章,博客,未经同意不得转载。
C++ Primer 学习笔记_29_STL实践与分析(3) --操作步骤集装箱(下一个)的更多相关文章
- C++ Primer 学习笔记_44_STL实践与分析(18)--再谈迭代器【下】
STL实践与分析 --再谈迭代器[下] 三.反向迭代器[续:习题] //P355 习题11.19 int main() { vector<int> iVec; for (vector< ...
- C++ Primer 学习笔记_41_STL实践与分析(15)--先来看看算法【下一个】
STL实践与分析 --初窥算法[下] 一.写容器元素的算法 一些算法写入元素值.在使用这些算法写元素时一定要当心.必须.写入输入序列的元素 写入到输入序列的算法本质上是安全的--仅仅会写入与指定输入范 ...
- C++ Primer 学习笔记_32_STL实践与分析(6) --再谈string类型(下)
STL实践与分析 --再谈string类型(下) 四.string类型的查找操作 string类型提供了6种查找函数,每种函数以不同形式的find命名.这些操作所有返回string::size_typ ...
- C++ Primer 学习笔记_35_STL实践与分析(9)--map种类(在)
STL实践与分析 --map类型(上) 引: map是键-值对的集合. map类型通常能够理解为关联数组:能够通过使用键作为下标来获取一个值,正如内置数组类型一样:而关联的本质在于元素的值与某个特定的 ...
- C++ Primer 学习笔记_43_STL实践与分析(17)--再谈迭代器【中】
STL实践与分析 --再谈迭代器[中] 二.iostream迭代[续] 3.ostream_iterator对象和ostream_iterator对象的使用 能够使用ostream_iterator对 ...
- C++ Primer 学习笔记_46_STL实践与分析(20)--容器特有的算法
STL实践与分析 --容器特有的算法 与其它顺序容器所支持的操作相比,标准库为list容器定义了更精细的操作集合,使它不必仅仅依赖于泛型操作.当中非常大的一个原因就是list容器不是依照内存中的顺序进 ...
- C++ Primer 学习笔记_40_STL实践与分析(14)--概要、先来看看算法【上】
STL实践与分析 --概述.初窥算法[上] 标准库容器定义的操作很少.并没有给容器加入大量的功能函数.而是选择提供一组算法,这些算法大都不依赖特定的容器类型,是"泛型"的. ...
- C++ Primer 学习笔记_45_STL实践与分析(19)--建筑常规算法
STL实践与分析 --泛型算法的结构 引言: 正如全部的容器都建立在一致的设计模式上一样,算法也具有共同的设计基础. 算法最主要的性质是须要使用的迭代器种类.全部算法都指定了它的每一个迭代器形參可使用 ...
- C++ Primer 学习笔记_33_STL实践与分析(7) --容器适配器
STL实践与分析 --容器适配器 引: 除了顺序容器.标准库还提供了三种顺序容器适配器:queue,priority_queue和stack.适配器是标准库中的概念.包含容器适配器,迭代器适配器和函数 ...
随机推荐
- 基本调试命令 - u/ub/uf
原:http://www.cnblogs.com/developersupport/p/windbgcommand-u.html 在调试过程中难免会遇到须要反编译代码来分析逻辑的时候.在windbg中 ...
- Cocos-2dx-Lua中使用Luaj的完整示例(转)
如何使用Luaj进行java与Lua之间的交互调用 一.主要分为两个大步骤,Lua工程的修改,android工程的修改 二.工程环境 开发工具:Cocos-Code-IDE Lua版本 : Lua 5 ...
- 用golang写的 分解x86 intel boot/recovery工具
源代码地址: https://github.com/sndnvaps/pack-unpack-intel
- C# 5.0 Async函数的提示和技巧
一.创建Async函数 Async是C# 5.0中新增的关键字,通过语法糖的形式简化异步编程,它有如下三种方式: async Task<T> MyReturningMethod { ret ...
- Android Java汉字转拼音总结
转载请表明出处:http://blog.csdn.net/lmj623565791/article/details/23187701 开发过程中有时候会遇到使用拼音模糊搜索等功能(典型的就是Andro ...
- 好玩的WPF第二弹:电子表字体显示时间+多彩呼吸灯特效button
我们先来看看Quartz MS字体动态显示系统时间的效果,难度相较于上一篇也要简单很多. 首先是定义一个TextBlock例如以下. <Grid> <TextBlock Name=& ...
- Duanxx的STM32学习: 启动模式,BOOT0和BOOT1具体解释
在画STM32的电路图的时候,关于STM32的启动方式纠结了一下,现有的參考设计都是在STM32的启动选择引脚BOOT0和BOOT1上使用了跳帽,用以人工选择STM32的启动方式,可是在实际应用中这样 ...
- 开源 自由 java CMS - FreeCMS1.9 评论管理
项目地址:http://code.google.com/p/freecms/ 评论管理 1. 评论管理 从左側管理菜单点击评论管理进入. 2. 评论审核 选择须要审核的评论,然后点击"审核& ...
- ASP.NET自定义控件组件开发 第三章 为控件添加事件 前篇
原文:ASP.NET自定义控件组件开发 第三章 为控件添加事件 前篇 第三章 为控件添加事件 好了,我们之前以前开发一个控件.而且也添加了属性,开发也很规范,但是那个控件还差最后一点:添加事件. 系列 ...
- 部署Redis主-从
Redis主-从部署实践 0. 前言 这篇文章简要介绍Redis的主从部署,实现了一主二从,使用两个哨兵监控,以实现简单的HA,其中从库作为备机. 1. 部署 这里有三台服务器,其中239主机上的Re ...