C++ Primer 学习笔记13 顺序容器





一、容器的初始化

顺序容器内的元素按其位置存储和访问。
顺序容器的元素排列次序与元素值无关,
为了使程序更清晰、简短、容器类型最常用的构造函数是默认构造函数。
容器构造函数

C<T> c;

创建一个名为c的空容器。C是容器类型名,vector,T是元素类型,intstring适用于所有容器

C c(c2);

创建容器c2的副本c;cc2必须具有相同的容器类型,并存放相同类型的元素。适用于所有容器。

C c(b,e);

创建c,其元素是迭代器be标示的范围内元素的副本。

适用于所有容器

C c(n, t);

n个值为t的元素创建容器c,其中值t必须是容器类型C的元素类型的值,或者是可转换为该类型的值。

只适用于顺序容器

C c(n);


创建有n个值初始化元素的容器c

只适用于顺序容器

1、将一个容器初始化为另一个容器的副本
    将一个容器复制给另一个容器时,类型必须匹配:容器类型和元素类型都必须完全相同。
	vector<int> ivec;
	vector<int> ivec2(ivec);	//OK
	vector<double> dvec(ivec);	//Error
	list<int> ilist(ivec);		//Error

2、初始化为一段元素的副本

    系统允许通过一对迭代器间接实现不同种容器之间进行复制:使用迭代器时,不要求容器类型相同,容器内元素类型也可以不相同,只要他们相互兼容,能够将要复制的元素转换为所构建的新容器的元素类型,即可实现复制。

    vector<string> svec;
    //...
    list<string> slist(svec.begin(),svec.end());	//OK

    vector<string>::iterator mid = svec.begin() + svec.size()/2;
    deque<string> front(svec.begin(),mid);			//OK
    deque<string> back(mid,svec.end());				//OK

    char *word[] = {"stately","plump","buck","mulligan"};
    list<string> slist2(word,word + sizeof(word)/sizeof(*word));	//OK   将数组长度加到指向第一个元素的指针上就可以得到指向超出数组末端的下一位置的指针

    vector<int> ivec;
    //...
    vector<double> dvec(ivec.begin(),ivec.end());	//OK

3、分配和初始化指定数目的元素

    不提供元素初始化式时,标准库将为该容器实现值初始化,采用这种类型的初始化,元素类型必须是内置或复合类型,或者是提供了默认构造函数的类类型。如果元素类型没有默认构造函数,则必须显式的指定其元素初始化式。

    接受容器大小做形参的构造函数只适用于顺序容器,而关联容器不支持这种初始化。

	const list<int>::size_type list_size = 64;
	list<int> ilist(list_size);		//OK
	list<string> slist(list_size);	//OK

        list<string> strList(list_size,"Ha~");	//OK

容器内元素的约束

    C++语言中,大多数类型都可用作容器的元素类型。容器元素类型必须满足

以下两个约束:

    •元素类型必须支持赋值运算。

    •元素类型的对象必须可以复制。

容器操作的特殊要求

    支持复制和赋值功能是容器元素类型的最低要求。此外,一些容器操作对元素类型还有特殊要求。如果元素类型不支持这些特殊要求,则相关的容器操作就不能执行:我们可以定义该类型的容器,但不能使用某些特定的操作。

class Foo
{
public:
    Foo(int x)
    {

    }
};

int main()
{
    vector<Foo> empty;		//OK
    vector<Foo> bad(10);	//Error
    vector<Foo> ok(10,1);	//OK
}

容器的容器

    因为容器受容器类型的约束,所以可定义元素是容器的容器:

	vector< vector<string> > vvec;

【注意:】

     在指定容器元素为容器类型时,必须如下使用空格:

	vector< vector<string> > vvec;		//OK
	vector< vector<string>> bad_vvec;	//Error

二、迭代器和迭代器范围

所有标准库都提供的迭代器运算

*iter

返回迭代器iter所指向的元素的引用

iter-> mem

iter进行解引用,获取指定元素中名为mem的成员。等效于(*iter).mem

++iter/iter++

iter1,使其指向容器里的下一个元素

--iter/iter--

iter1,使其指向容器里的前一个元素

iter1== iter2

iter1!= iter2             

比较两个迭代器是否相等(或不等)。当两个迭代器指向同一个iter2容器中的同一个元素,或者当它们都指向同一个容器的超出末端的下一位置时,两个迭代器相等.



   vectordeque类型迭代器支持的操作

iter+ n

iter- n

在迭代器上加()整数值n,将产生指向容器中前面(后面)n个元素的迭代器。新计算出来的迭代器必须指向容器中的元素或超出容器末端的下一位置

iter1+= iter2

iter1-= iter2

这里迭代器加减法的复合赋值运算:iter1加上或减去iter2的运算结果赋给iter1

iter1- iter2

两个迭代器的减法,其运算结果加上右边的迭代器即得左边的迭代器。这两个迭代器必须指向同一个容器中的元素或超出容器末端的下一位置

只适用于vectordeque容器

>,>=,<,<=

迭代器的关系操作符。当一个迭代器指向的元素在容器中位于另一个迭代器指向的元素之前,则前一个迭代器小于后一个迭代器。关系操作符的两个迭代器必须指向同一个容器中的元素或超出容器末端的下一位置

只适用于vectordeque容器

关系操作符只适用于vectordeque容器,因为只有这两种容器为其元素提供快速、随机的访问。
   
    vector<int> ivec;
    //...
    vector<int>::iterator mid = ivec.begin() + ivec.size()/2;	//OK

    list<int> ilist(ivec.begin(),ivec.end());
    list<int>::iterator iter = ilist.begin() + ilist.size()/2;	//Error
    list<int>::iterator iter1 = ilist.begin(),
                        iter2 = ilist.end();
    if (iter1 < iter2)	//Error
    {
        //...
    }
 list容器的迭代器既不支持算术运算符,也不支持关系运算符,它只是提供前置/后置的自增、自减运算以及相等/不等运算。

对形成迭代器范围的迭代器的要求

迭代器 firstlast如果满足以下条件,则可形成一个迭代器范围:

    •它们指向同一个容器中的元素或超出末端的下一位置。

    •如果这两个迭代器不相等,则对first反复做自增运算必须能够到达last。换句话说,在容器中,last绝对不能位于first之 前。

使用左闭右开区间的意义

[first,last)

    1)当firstlast相等,迭代器范围为空

    2)当firstlast不相等时,迭代器范围内至少有一个元素:size= last – fist

使迭代器失效的容器操作

    一些容器的操作会修改容器的内在状态或移动容器内的元素。这样的操作使所有指向被移动的元素的迭代器失效,也可能同时使其他迭代器失效。使用无效迭代器是没有定义的,可能会导致与悬垂指针相同的问题。使用无效迭代器将会导致严重的运行时错误。

    无法检查迭代器是否有效,也无法通过测试来发现迭代器是否已经失效。任何无效迭代器的使用都可能导致运行时错误,但程序不一定会崩溃,否则检查这种错误也许会容易些...

【建议:】

    使用迭代器时,通常可以编写程序使得要求迭代器有效的代码范围相对较短。 然后,在该范围内,严格检查每一条语句,判断是否有元素添加或删除,从而相应地调整迭代器的值

三、顺序容器
  
  

每种顺序容器都提供了一组有用的类型定义以及以下操作:

    1)在容器内添加元素;

    2)在容器中删除元素;

    3)设置容器的大小;

    4)(如果有的话)获取容器内的第一个和最后一个元素。

1、容器定义的类型别名

所有容器都提供的类型别名

size_type

无符号整型,足以存储容器类型的最大可能容器长度

iterator

容器的迭代器类型

const_iterator

容器的只读迭代器类型

reverse_iterator

按逆序寻址元素的迭代器类型

const_reverse_iterator

元素的只读逆序迭代器

difference_type

足够存储两个迭代器差值的有符号整型,可为负数

value_type

元素类型

reference

元素的左值类型,是value_type&的同义词

const_reference

元素的常量左值类型,等效于constvalue_type&


逆序迭代器从后向前遍历容器,并反转了某些相关的迭代器操作,例如,在逆序迭代器上做++运 算将指向容器中的前一个元素。

表中最后三种类型使程序员无须直接知道容器元素的真正类型,就能使用它。需要使用元素类型时,只要用value_type即可。如果要引用该类型,则通过referenceconst_reference类型实现。在程序员编写自己的泛型程序时,这些元素相关类型的定义非常有用。

    vector<string>::iterator iter;
    vector<int>::difference_type cnt;

2、beginend成员

容器的beginend成员

c.begin()

返回一个迭代器,它指向容器c的第一个元素

c.end()

返回一个迭代器,它指向容器c最后一个元素的下一位置

c.rbegin()

返回一个逆序迭代器,它指向容器c最后一个元素

而不是下一位置!

c.rend()

返回一个逆序迭代器,它指向容器c第一个元素前面的位置

而不是第一个元素!

    上述每个操作都有两个不同版本:一个是const成员,另一个是非 const成员。这些操作返回什么类型取决于容器是否为const。如果容器不是const,则这些操作返回iteratorreverse_iterator类型。如果容器是 const,则其返回类型要加上const_前缀,也就是const_iteratorconst_reverse_iterator类型。


3、在顺序容器中添加元素


在顺序容器中添加元素的操作

c.push_back(t)

在容器c的尾部添加值为t的元素。返回void类型

c.push_front(t)

在容器c前端插入值为t的元素。返回void类型。

只适用于listdeque容器类型。

c.insert(p,t)

在迭代器p所指向的元素前面插入值为t的新元素,返回指向新添加元素的迭代器。

c.insert(p,n,t)

在迭代器p所指向的元素前面插入n个值为t的新元素,返回void

c.insert(p,b,e)

在迭代器p所指向的元素前面插入迭代器be标记的范围内的元素,返回void

【关键概念】容器元素都是副本

     在容器中添加元素时,系统是将元素值复制到容器里。类似地,使用一段元素初始化新容器时,新容器存放的是原始元素的副本。被复制的原始值与新容器中的元素各不相关,此后,容器内元素值发生变化时,被复制的原值不会受到影响,反之亦然。

    list<int> iList;
    for (int i = 0; i != 10; ++i)
    {
        iList.push_back(i);
        iList.push_front(i);
    }
    for (list<int>::const_iterator iter = iList.begin(); iter != iList.end(); ++iter)
    {
        cout << *iter << endl;
    }

1)、在容器中的指定位置添加元素
	vector<string> strVec;
	list<string> strList;
	string val("Beth");
	
	//	strList.insert(strList.begin(),val);
	strList.push_front(val);
	strVec.insert(strVec.begin(),val);	//这个操作的代价是很昂贵的
2)、插入一段元素
	//1
	vector<string> strVec;
	strVec.insert(strVec.end(),10,"Ha~");

    //2
    list<string> strList;
    vector<string> strVec;
    string sarray[4] = {"quasi","simba","frollo","scar"};

    strList.insert(strList.end(),sarray,sarray+4);
    strVec.insert(strVec.end(),strList.begin(),strList.end());

3)、添加元素可能会使迭代器失效

     vector容器中添加元素可能会导致整个容器的重新加载,这样的话,该容器所涉及到的所有迭代器都会失效!即使不需要重新加载整个容器,指向新插入元素后面的迭代器也会失效!

任何insertpush操作都可能导致迭代器失效,因此在编写循环将元素插入到vectordeque容器中时,程序必须确保迭代器在每次循环后都得到更新。

4)、避免存储end操作返回的迭代器

    在容器的任何位置插入任何元素都会使end迭代器失效!!!

    vector<int>::iterator first = iVec.begin(),
                          last = iVec.end();

	//程序运行期间可能崩溃
	while (first != last)
	{
		first = iVec.insert(++first,42);
		++ first;
	}
/*
*添加元素会使得存储在last中的迭代器失效,
*该迭代器既没有指向容器iVec的元素,
*也不再指向iVec的超出末端的下一个位置
*/

	//正确的写法
    vector<int>::iterator first = iVec.begin();

	while (first != iVec.end())
	{
		first = iVec.insert(++first,42);
		++ first;
	}

4、关系操作符

 所有的容器类型都支持用关系操作符来实现两个容器的比较。比较的容器必须具有相同的容器类型,而且其元素类型也必须相同。例如,vector<int> 容器只能与vector<int>容器比较,而不能与list<int>或 vector<double>容器比较。

      容器的比较是基于容器内元素的比较。容器的比较使用了元素类型定义的同一个关系操作符:两个容器做!=比较使用了其元素类型定义的!=操作符。如果容器的元素类型不支持某种操作符,则该容器就不能做这种比较运算。

下面的操作类似于string类型的关系运算:

    •如果两个容器具有相同的长度而且所有元素都相等,那么这两个容器就相等;否则,它们就不相等。

    •如果两个容器的长度不相同,较短的容器中所有元素都等于较长容器中对应的元素,则称较短的容器小于另一个容器。

    •如果两个容器都不是对方的初始子序列,则它们的比较结果取决于所比较的第一个不相等的元素。

5、容器大小的操作

所有容器都提供的大小操作

c.size()

返回容器c中的元素个数。返回类型为c::size_type

c.max_size()

返回容器c可容纳的最多元素个数,返回类型为c::size_type

c.empty()

返回标记容器大小是否为0的布尔值

c.resize(n)

调整容器c的长度大小,使其能容纳n个元素,如果n<c.size(), 则删除多出来的元素;否则,添加采用值初始化的新元素

c.resize(n,t)

调整容器c的长度大小,使其能容纳n个元素。所有新添加的元素值都为t


list <int> ilist(10,42);
ilist.resize(15);       //后面添加5个0
ilist.resize(25,-1);      //后面添加10个-1
ilist.resize(6);         //后面擦除20个元素

使用resize操作可能会使迭代器失效,在vectordeque容器上做的resize操作有可能会使得所有的迭代器都失效!

    对于所有的容器类型,如果resize操作压缩了容器,则指向已删除的元素的迭代器会失效




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
信息数据从传统到当代,是一直在变革当中,突如其来的互联网让传统的信息管理看到了革命性的曙光,因为传统信息管理从时效性,还是安全性,还是可操作性等各个方面来讲,遇到了互联网时代才发现能补上自古以来的短板,有效的提升管理的效率和业务水平。传统的管理模式,时间越久管理的内容越多,也需要更多的人来对数据进行整理,并且数据的汇总查询方面效率也是极其的低下,并且数据安全方面永远不会保证安全性能。结合数据内容管理的种种缺点,在互联网时代都可以得到有效的补充。结合先进的互联网技术,开发符合需求的软件,让数据内容管理不管是从录入的及时性,查看的及时性还是汇总分析的及时性,都能让正确率达到最高,管理更加的科学和便捷。本次开发的医院后台管理系统实现了病房管理、病例管理、处方管理、字典管理、公告信息管理、患者管理、药品管理、医生管理、预约医生管理、住院管理、管理员管理等功能。系统用到了关系型数据库中王者MySql作为系统的数据库,有效的对数据进行安全的存储,有效的备份,对数据可靠性方面得到了保证。并且程序也具备程序需求的所有功能,使得操作性还是安全性都大大提高,让医院后台管理系统更能从理念走到现实,确确实实的让人们提升信息处理效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值