C++学习笔记-容器

来源:互联网 发布:cici网络里是什么意思 编辑:程序博客网 时间:2024/05/17 04:05

顺序容器的类型

vector

deque

list

forward_list

array

string

比较:

string和vector中的元素顺序存储,能够快速随机访问。在中间位置添加,插入或删除元素非常耗时

list和forward_list不支持元素的随机访问。为了访问一个元素,必须遍历整个容器。能非常快速地在容器任何位置添加和删除元素

deque能够快速随机访问。在中间位置添加,插入或删除元素的代价可能很高。但是,在deque的两端添加或删除元素都是很快的

array是一种更安全、更容易使用的数组结构。大小固定,不支持添加和删除元素,以及改变容器大小的操作。

确定使用哪种顺序容器

通常,使用vector是最好的选择

如果不确定应该使用哪种容器,那么在程序中只使用vector和list公共的操作,无论最后决定用vector还是决定用list,程序都不用做大的改动。

容器均是模板类。对大多数,但不是所有容器,我们需要提供元素类型信息

vector<int> iv;

迭代器范围

一个迭代器范围用一对迭代器表示。两个迭代器分别指向同一个容器中的元素或者是尾元素之后的位置

假设begin和end构成一个合法的迭代器范围,那么有如下性质

  • 若begin和end相等,则范围为空
  • 若两者不相等,则范围内至少有一个元素。且begin指向该范围内的第一个元素
  • 对begin递增若干次,最终能使得begin==end

容器定义和初始化

默认构造函数

C c;   例vector<int> iv;

将一个容器初始化为另一个容器的拷贝

C c1(c2)或者 C c(beg,end)   例vecor<int> iv2(iv1)  或者vecor<int> iv2(iv1.begin,iv1.end)

当将一个容器初始化为另一个容器的拷贝时,两个容器的容器元素类型和元素类型必须相同。

如果传递迭代器参数来拷贝一个范围,那么只要求被拷贝的元素能转换成要初始化的容器的元素类型。

列表初始化

C c={元素列表};例 vector<int> iv={1,2,3} ,则iv有三个元素

与顺序容器大小相关的构造函数

C seq(n) 其中n是容器大小  例  vector<string> sv(5);

C seq(n,t)  其中n是容器大小,t是元素初始值     例   vector<string> sv(5,"hello");

array的构造函数

除了指定元素类型,同时要指定容器大小

array<int,42>  ial;   //42个元素都是0

array<int,42>  ial={1,2,3}   //使用的列表初始化。前三个元素分别是1,2,3,后面的39个元素都是0

可以复制array对象

array<int,42>  ial2=ial;

赋值,交换和替换

赋值

c1=c2;

c1={a,b,c};//array不支持

注意,赋值要求左右两边容器的类型相同,但不要求大小相同。赋值运算后,左右两边容器的大小都等于右边容器大小。

赋值操作适用于所有容器(除array不支持c1={a,b,c}的情形外)

赋值操作会导致指向左边容器内部的迭代器、引用和指针失效

交换

swap(c1,c2);

c1.swqp(c2);

交换c1和c2中的元素。两者必须具有相同的类型,不必拥有相同大小

交换元素的速度比拷贝元素的速度快得多。因为除array外,swap不对任何元素进行拷贝、删除或插入操作。元素本身未交换,只是交换了两个容器的内部数据结构

所有容器都支持

元素没有被移动,所以,除string外,指向容器的迭代器,引用和指针在swap操作之后都不会失效,但是所属的容器改变了。迭代器指向另一个容器的那个位置。

替换

seq.assign(b,e);  //b,e是一对迭代器范围

seq.assign(il);  //il是初始化列表

seq.assign(n,t)   //将seq中的元素替换为n个值为t 的元素

assign操作用参数所指定的元素替换左边容器中的所有元素。要求右边容器的元素类型与左边相容(能转换成左边元素的类型)。右边元素的个数不限制。既可以比左边容器中元素多,也可以比左边容器中元素少。

 除array外的所有顺序容器都支持。

关系运算符

所有容器都支持==和!=、除无序关联容器外,所有容器都支持关系运算符(>,>=,<,<=)

关系运算符左右两边的运算对象必须是相同类型的容器。

容器的比较,实际上是其中相应位置的元素的比较。因此,如果元素类型不支持所需运算符,那么容器就不能用相应的运算符进行比较。

顺序容器的操作

添加元素

push_back

除array和forward_list之外,每个顺序容器都支持push_back。push_back将一个对象(的拷贝而非对象本身)追加到容器的尾部。

vector和string的下标运算符必须在合理范围,不能超过size()的返回值-1。因此,不能用下标向其添加元素。可用push_back添加元素

push_front

list,forward_list,和deque还支持push_front.将元素插入到容器头部

insert

将元素插入到迭代器指定位置之前

对不支持push_front的容器,可用insert(svec.begin(),要插入的元素);将元素插入到容器的开始位置

emplace操作

emplace_front,emplace和emplace_back构造元素,分别将元素放在容器头部,指定位置之前和容器尾部。

这三个函数的参数必须与元素类型的构造函数相匹配


vector<string> vs;

vs.emplace_front("hello");

访问容器中的元素

c.front();

c.back();

c[n]

c.at(n)

每个顺序容器都有front(),除forward_list外的所有顺序容器都有back()。at和下标操作只适用于string,vector,deque和array

注意如果容器不是const的,则以上访问成员函数返回的是引用。

注意,不要对空容器调用front和back。调用at和下标操作时,要保证下标不越界。

删除元素

c.pop_back()  //删除尾元素,返回void

c.pop_front()  //删除首元素,返回void

c.erase(p) //删除迭代器p指向的元素。返回一个指向被删除元素之后元素的迭代器

c.erase(b,e)  //删除迭代器范围内的元素。返回指向最后一个被删除元素之后元素的迭代器

c.clear()  //删除c中所有元素,返回void

注意,不要对空容器执行pop_back() 和pop_front() 。从容器内部删除元素用erase函数。删除所有元素用clear()
特殊的forward_list操作

在一个forward_list中添加和删除元素的操作是通过改变给定元素之后 的元素完成的。所以,forward_list的操作是在给定迭代器之后添加或删除元素。

例:

lst.insert_after(p,t)  //返回指向被插入的元素的迭代器

emplace_after(p,args)  //返回指向新元素的迭代器

lst.erase_after(p) //返回指向被删除元素之后元素的迭代器

forward_list还提供了一个函数,获取首元素之前不存在的的元素的迭代器:

lst.before_begin()

容器操作可能使迭代器失效

向vector和string中插入或删除元素时,被插入或删除的元素之前的迭代器,引用和指针仍然有效

对于deque,在首尾添加元素,迭代器会失效,但是指向已存在的元素的引用和指针不会失效。在首尾删除元素,迭代器,指针和引用不受影响(删除尾元素时,只有尾后迭代器器失效)。在其它任何位置添加或删除元素都会造成迭代器、引用和指针失效

对于list和forward_list,添加或删除元素之后,指向容器的迭代器(包括尾后迭代器和首前迭代器)、指针和引用仍有效

如果在一个循环中插入或删除vector,string或deque中的元素,不要缓存end返回 的迭代器,必须在每次操作后都重新调用end函数。

使用插入或删除函数的返回值,可以操作改变后的顺序容器中的元素。

vector管理容量的成员函数

vector和string容器中的元素是连续存储的.当没有空间容纳新的元素时,容器会分配新的空间来保存已有元素和新元素,将已有元素从旧位置移动到新空间中,然后添加新的元素,释放旧空间。每次获取新的空间时,vector和string通常会分配比新的空间需求更大的内存空间。

c.size()  //容器已经保存的元素的数目

c.capacity()  //容器在不分配新的内存的前提下最多可以保存多少元素

c.reserve(n)   //分配至少容纳n个元素的内存空间

c.shrink_to_fit()  //将capacity()减少为与size()相同大小

以上函数中,c.shrink_to_fit() 只适用于vector,string和deque.而capacity和reserve只适用于vector和string

注意,当n>c.capacity()时,reserve调用才会改变vector的容量。当n<c.capacity()时,reserve调用什么也不做。

容器适配器

一个容器适配器接受一种类型,使其行为看起来像一种不同的类型

定义适配器

deque<int> deq;

stack<int> stk;  //空对象

stack<int> stk2(deq);   //用deque对象来初始化一个新的stack

默认情况下,stack和queue是基于deque实现的。priority_queue是在vector之上实现的。也可以重载默认容器类型

vector<string>  s(5,"hello");

stack<string, vector<string>> str_stk;

stack<string, vector<string>> str_stk2(s);

stack可以使用除array和forward_list之外的任何一种容器类型来构造。queue可以基于list和queue来构造。priority_queue可以构造于vector和queue.

stack定义在头文件stack中。queue和priority_queue定义在queue头文件中。

stack是后入先出。queue的策略是先进先出。进入队列的被放置到队尾,而离开队列的则从队首删除。

priority_queue中,新加入的元素会排在所有优先级比它低的已有元素之前。调用pop会删除优先级最高的元素。

0 0
原创粉丝点击