重拾C++ 顺序容器

C++标准库string
与其它常见的初始化方式不同的是,其提供可字符重复(及次数)的初始化方法。其是否使用"="进行初始化与构造函数
的设定有关。(注意初始化时不能使字符串重复初始化而来)
类的初始化方式兼有声明的作用,即同时声明并初始化类实例,这对一些脚本语言(python:基本没有声明的意义,运行时解析)
是无用的。


string具有字符粘贴能力(python 同样有),这为多行输入提供了方便。
string(有size empty方法)与一般脚本str的不同在于,其提供了getline函数,可以输入流(cin或一些文件输入流)作为第一个参数,第二个是输入对象,
这样读入输入流的第一行。这个函数可以用于循环输入(搭配while循环)。
关于string提供的"+"运算符,值得注意的是不能直接对两个字符串常量直接使用,其非string类型。


C++中cctype.h中定义了若干对字符进行判断处理的函数。(include时去掉.h)
由于标准库string提供的方法仅此而已,所以对字符串中的字符进行处理多依赖于cctype库,遍历的操作多依赖于范围for循环。
(进行改变时使用引用:&,这可以对照于python的处理)
还有另外一种处理方式,利用迭代器及algorithm for_each函数但这里需要注意的是,要对其进行修改(toupper)需要将参数设定为引用。
(这也是合理的)这里虽然没有明确说明,但是sting vector等都具有begin end等迭代器。


迭代器与指针类似,(* -> ++ == !=)在对迭代器进行增减循环(一般会利用for_each进行替代)时判断条件多要采用"!=",而非没有规定序
的"<"。


迭代器类型:对于每一个容器,相对应的有迭代器,(Ex : vector::iterator)相应的const迭代器(vector::const_iterator)
与const指针相似,不能对指向的元素进行修改。(相应地对应于cbegin、cend)
这里操作指向的成员多使用->,否则在使用*要加"()"规定优先级(否则出错)
任何想要改变vector大小的操作都会使迭代器失效。
迭代器的基本运算与指针相似,特别地都被重载了 "+="等运算符。


剩余的部分涉及与旧的C的接口,不推荐使用(strlen, strcmp ...)






顺序容器:
顺序容器主要包括(vector deque list forward_list array string)
list不支持随机访问。


考虑对容器的不同处理,list类支持快速地对中间的元素进行修改,但考虑考虑快速随机访问应当对vector类进行。
推荐使用vector 对于在中间插入的情况,推荐对有序时在尾部插入,再利用sort(重载序运算)
无序插入,先对list进行操作,再拷贝到vector中。
在不确定使用哪种容器时,在代码中多使用迭代器,以为修改提供方便。


对容器进行初始化时,一般当只有个数时,相应的类要有默认构造函数,也可以没有,而将除个数外第二个参数指定为用来初始化的
值,即所谓初始化器。


容器有一些通用的相应类型组件,reference是一个,它与iterator相对,用于保持在容器外修改元素的能力。
当然相应的简单方法是auto引用。value_type可以表明元素类型。
这些组件多用于泛型编程中。


容器具有构造拷贝的方法,这种形式可以考虑为构造接口的统一。(如利用向量与矩阵初始化向量)


交换元素的方法为简单的swap,在形式上不用拷贝临时变量进行交换。
常用的对元素操作方法,insert erease(delete) clear emplace(向元素进行写运算 但是是以构造函数参数的形式 而非直接初始化临时对象的方法)
对于顺序容器的迭代器有自增减能力(forward_list除外)


const_iterator 在配合auto方面是有用的,否则准确的类型推断是复杂的。


对顺序容器元素进行初始化当具有形式C c(,,...)时是有三重含义的,
    构造函数初始化列表,
    若干个具有初始值的元素,
    在两个迭代器间的拷贝初始化。(这种初始化方法不要求两个容器元素类型完全相同,只要能进行转换即可)


上面所提到的类型转换与类的其它类型初始化是不同的,其多应用于不能直接运算的操作符,进行类型转换。
其与操作符重载形式相近但不同。其返回值类型在operator后面,没有参数,具有如下形式: operator int(){return real;}


seq暂时不被Code Blocks所支持 暂时不涉及,而且其初始化方法与上面讨论的重复。




对顺序容器的初始化,有一个特例,为array。其在初始化时必须在模板出给出大小:array
且有默认构造函数的类支持初始化空array。


顺序容器中除了array外的容器支持assign方法,将容器替换为相应的形式(是一种完全的替换),其有如下三种形式:
    seq.assign(iterator_begin, iterator_end)
    seq.assign(num, val)
    seq,assign({......})
由于固定大小的限制array不适用assign


swap方法有两种调用形式,但都是对同一种容器使用的。其速度一般比单纯的拷贝快得多。(毕竟相同类型)
swap方法的具体实现对array及其他顺序容器是不同的,对其它顺序容器可以理解为换了名称,而对array,是进行了元素
的拷贝替换,这使得指向容器元素的迭代器在swap前后的表现不同。
对于其它容器,即使进行了swap,指向的元素也是不变的(未交换),对array,指向的元素由于拷贝赋值而改变。
上面的现象对string的操作与array也是一样的。(string不属于标准库容器,已经进行了模板实例化并封装)


顺序容器支持关系运算符比较,其是基于元素封装的关系运算符的,基本符合类字典序。


顺序容器的添加元素操作值得注意的是emplace_back(emplace)
对于插入操作地点的方便记忆方法是,由于迭代器范围导致的插入必须在前面进行。
插入操作与前面的操作相同支持:范围插入,多个同值插入,列表插入。(insert)
考虑到性能问题,对于使用insert()的情况,尽量对list进行。
相应地删除方法:erase(具备单个迭代器删除及范围删除,返回指向删除后元素的迭代器)、clear


在直接利用erase方法删除容器中的元素的情况下,但重复删除时,可能存在迭代器失效的情况,
要使用erase删除元素,一种比较麻烦的方法需要指定两个迭代器,一个用于删除,一个用于指向。
        vectorvi0{1, 1, 5, 6, 5};
        vector::iterator vii = vi0.begin();
        vector::iterator viii = vi0.begin();




        while(viii != vi0.end())
        {
                if ((*vii) == 5)
                {
                        vi0.erase(vii);
                        vii = viii;
                }
                else{
                viii++;
                vii = viii;
                }


        }




另一种可以利用erase的返回值
        vectorvi{10, 11, 12, 9, 8};
        vector::iterator vii = vi.begin();
        while(vii != vi.end())
        {
                if ((*vii) % 2 == 0)
                        vii = vi.erase(vii);
                else
                        ++vii;
        }




由于删除容易出错,故推荐使用标准库algorithm remove方法,remove的具体实现应容器而异,vector remove实现元素移动而非删除,
list remove实现删除(解节点)。
对vector当同时使用两个时(先remove再erase),可以实现元素删除。


对于改变容器大小的操作可能使迭代器失效的问题,要应用(insert erase等的返回迭代器进行处理)
一般的,对于容器元素的操作导致迭代器失效的情况,需要考虑容器的类型,复制、拷贝、解节点这些数据结构底层特性是需要考虑的。


顺序容器提供除了迭代器解引用外的访问首尾元素的方法:front() back() 当容器为空时操作的行为未定义。
对于支持下标运算的容器,类似于dict get方法有相对安全的访问下标方法(.at(num) 如元素不存在,抛出异常)
这里在使用类型推断auto时也要注意改变值要使用引用。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值