C++基础补漏(六)——STL库中几种容器

来源:互联网 发布:网络优化师发展 编辑:程序博客网 时间:2024/05/03 00:22

C++的STL库:迭代器,顺序容器,关联容器,泛型算法等



————————————————————————————

一个容器就是一些特定类型对象的集合。


30.顺序容器

顺序容器提供了控制元素存储和快速访问顺序的能力。

主要的顺序容器:(橙色标注的是比较重要的)

vector: 可变大小数组,随机访问快,尾部之外的位置操作速度慢

deque: 双端队列。可以支持快速随机访问。头尾操作速度很快。

list: 双向链表。只支持双向顺序访问,在任何位置操作速度都很快。

forward_list: 单项链表。只支持单向顺序访问,在任何位置操作速度都很快。

array: 固定大小数组,支持快速随机访问。但不能添加或删除元素

string: vector相似的容器,但专门用来存字符。

 

上述顺序容器主要是在支持随机访问和任意位置操作的问题上有着不同的性能。

注:通常情况下,没有更好理由选择别的容器,最好选择vector。一般list也比较常用。

 

容器均为模板类,几乎可以保存任意类型,也可以是容器的类型。

语法:

vector<int> v1;

list <vector<double> >  l1;

 

每个容器都定义了多个类型,就是在模板类里的typedef



容器初始化:({}类初值的做法编译器版本不够)

C c;         //空容器

C c(b,e);     //迭代器范围构造

C c(n);        //构造一个n个元素的容器

C c(n,t);      //构造n个元素,每个元素的值都是t



array容器:

array不支持普通容器的构造函数,同时容器大小不可变

定义一个array时需要指定元素类型和容器大小:

array<int, 4> a = {"aaa", "bbb", "ccc", "ddd"}; //保存10个int元素的数组,可以向数组一样赋值

*注:array和普通数组的差别:多了操作


容器支持swap(需要相同容器交换),assign(可以从不同但相容类型或子序列赋值,arrary不行),运算符比较,动态添加和删除元素,访问元素(下标访问,.at访问),改变容量大小(array不行)

删除:

int main(){vector<int> aa;aa.push_back(1);aa.push_back(2);aa.push_back(3);aa.push_back(4);aa.push_back(5);aa.push_back(6);vector<int>::iterator it1 = ++aa.begin();vector<int>::iterator it2 = it1 + 3;aa.erase(it1,it2);}

结果:aa里的容量为6, 元素为1,5,6,容量不会改变(应该是分配的内存,元素数量改变)

因为容器标准库采用了可以减少容量空间重新分配次数的策略:当不得不获取新的内存空间时,会申请分配更大的内存空间,这些预留空间可以作为备用,来保存更多元素。


容器适配器:

概念:适配器是一种机制,能使某种事物的行为看起来像另一种事物。一个容器适配器接受一种已有的容器类型,使其行为看起来像一种不同的类型。

          默认情况下stack和queue是基于deque实现的,priority_queue基于vector实现的。

标准库定义了三个顺序容器适配器:stack,queue和priority_queue。

定义一个适配器:

deque<int> deq;       //定义一个双端队列的容器

stack<int> stk(deq);     //定义个适配器,元素从deq中拷贝

stack<string, vector<string> > stk1(svec);     //stk1在vector上实现,初始化时保存svec的值

创建适配器时讲一个命名的顺序容器作为第二个类型参数,来重载默认容器类型。每个容器适配器都基于底层容器类型的操作定义了自己的特殊操作。



31.迭代器

迭代器可以实现对容器元素的访问。

STL里的容器都可以使用迭代器,但只有少数几种才支持下标。

使用迭代器可以访问某个元素也可以从一个元素移动到另一个元素。

迭代器分为有效和无效两种。有效迭代器指向某个元素或者指向容器中尾元素的下个位置。其他属于无效。

 

每个迭代器都有一个beginend的成员。begin成员返回指向第一个元素,end成员返回指向尾元素的下个位置,返回的迭代器也成为尾后迭代器。

注:空容器beginend返回的是同一个迭代器,都是尾后迭代器。

 

 

迭代器的操作:(操作类似于指针)

*iter      返回迭代器指向的元素(end返回的迭代器除外)

++iter       iter指向容器中的下一个元素

--iter      iter指向容器中的上一个元素

iter1 == iter2   判2个迭代器是否相同

 

迭代器的类型:

迭代器有2iteratorconst_iterator

 vector<int>::iterator it1;             //能读写的迭代器

 vector<int>::const_iterator it2;       //只能读不能写的迭代器

使用:

vector<int> v;

vector<int>::iterator iter1 = v.begin();   //把容器vbegin返回迭代器赋值给iter1

Vector<int>::iterator iter2 = v.end();    //把容器vend返回迭代器赋值给iter2

while(iter1 != iter2)

{

...//操作

++iter1;

}

 

注:迭代器的使用方式都是和指向容器的指针一样。只不过迭代器能保证在容器的有效范围内。迭代器的范围由一对迭代器表示:biginend



32.泛型算法

概念:标准库未给每个容器提供大量功能,而是提供了一组算法,这些算法大多都独立于任何特定的容器,而且是通用的。

            之所以称之为算法是因为他们实现了一些经典算法的公共接口

算法使用了迭代器使操作不依赖于容器。算法永远不会改变底层容器的大小,但可能改变容器中保存的元素值,或移动位置,但永远不会添加删除元素。





33.关联容器

关联容器和顺序容器根本的不同:关联容器中元素是按关键字来保存和访问的;顺序容器中的元素是按他们在容器中的位置来顺序保存和访问的。虽然两者的很多行为相同,但其不同之处是关键字

概念:关联容器支持高校的关键字查找和访问

两种主要的关联容器:map, set。

map中的元素是一些关键字-值(key-value)对:关键值起到索引的作用,值是与索引相关联的数据。

set中每个元素值只包含一个关键字,它支持高效的关键字查询操作。

根据有没有重复关键字,是否有序保存,有分为了8种关联容器

map, set, multimap, multiset, unordered_map, unordered_set,unordered_mulitmap,unordered_multiset

*注:无序容器使用哈希函数来组织的。

map:
定义:
map<string, int> m1;    //创建关键字是string类型,值是int类型的空容器
其中第一个模板参数类型是关键字类型,后面一个模板参数类型是值的类型,且必须都要指明。map不允许重复关键字,multimap用来存储重复的关键字的map。

map使用pair类来保存成员:
pair有两个public的数据成员分别为first,secod。
pair是一个用来生成特定类型的模板。如:
pair<string, int> p1;

注:在对map的对象进行下标操作时,如果原来map中没有,则会自动为他创建一个新元素,其关键字为下标操作的值,值为0。


set:

定义:set<string> set1;


关联容器额外类型别名:

key_type:此容器类型的关键字类型

mapped_type:每个关键字关联的类型,只是适用于map

value_type:对于set,与key_type相同;对于map为 pair<const key_type, mapped_type>

注:因为不能改变关键字值,所以pair关键字部分是const。


关联容器支持添加(insert)和删除(erase)元素操作

下标操作:map和unordered_map支持下标运算符合at函数。(下标可接受一个索引)

                   set类型不支持下标

此外,也可用对map用find来代替下标操作。



2 0
原创粉丝点击