顺序容器和关联容器

顺序容器:vector;list;deque(双向口队列);queue(单向口队列);stack(栈 );heap(堆);priority_queue (按键值大小排序)

关联容器:set;map;multiset;multimap;

set和map 的insert/erase

set.insert(int x);//直接插入数值
set.insert(iterator position,int x);// 第一位为迭代器位置
set.insert(iterator first,iterator last);//迭代器区域

set.erase(int x);// 直接删除数值
set.erase(iterator position);// 迭代器位置
set.erase(iterator first,iterator last);

iterator set.find(int x);// 返回迭代器索引。使用关联式容器自带的find函数比STL只会循序搜索高效
int set.count(int x); // 返回数值,几个
iterator set.lower_bound(int x); // 返回迭代器索引
iterator set.upper_bound(int x);

 vector的insert/erase

// insert必须要有位置的迭代器
vector.insert(iterator pos,elem);   //在pos位置前插入一个elem元素的拷贝,返回新数据的位置。
vector.insert(iterator pos,n,elem);   //在pos位置前插入n个elem数据,无返回值。
vector.insert(iterator pos,beg,end);   //在pos位置前插入[beg,end)区间的数据,无返回值 

// erase参数都是迭代器
vec.erase(beg,end);  //删除[beg,end)区间的数据,返回下一个数据的位置。
vec.erase(pos);    //删除pos位置的数据,返回下一个数据的位置。

 

顺序容器

0、容器的赋值、swap、assign

vector容器并不像数组一样,可以通过下标操作进行赋值或者添加元素,vector容器的下标操作只是用来访问的。

顺序容器的赋值操作:

Swap

vector<string> svec1(10);
vector<string> svec2(24);
swap(svec1,svec2);

结果:svec1中将包含24个string元素,svec2中10个。且操作很快。

1、要求两个相同类型容器

2、元素本身并未交换,swap只交换了两个容器的内部数据结构。

      指向容器的迭代器、引用和指针在swap之后不会失效,仍指向操作之前指向的那些元素,但是这些元素属于不同容器了。

一、顺序容器操作

顺序容器不依赖于元素的值,而是与元素加入容器的位置相对应。

参数貌似都是迭代器类型。

1、添加元素

c.push_back(t) 在c的尾部创建一个值为t的元素

c.push_front(t) 在c的头部创建一个值为t的元素

c.insert(p,t) 迭代器p指向的元素之前创建一个值为t的元素,返回指向新添加的元素的迭代器

insert实现了在容器的任意位置添加元素。第一个元素是指定要插入元素的迭代器位置。第二个元素为范围或者值元素。

2、访问元素

c.back()           返回c中尾元素的引用。若c为空,函数行为未定义

c.front()           返回c中首元素的引用。若c为空,函数行为未定义

c[n]             返回c中下标为n的元素的引用,n是一个无符号整数。若n>c.size(),则函数的行为未定义          

c.at[n]            返回下标为n的元素的引用。如果下标越界,则抛出一个out_of_range异常
 

注意:容器内访问元素的成员函数(back、front、[]、.at())返回的都是引用

auto &u=c.back()需要将变量定义为引用类型。

3、删除元素

c.pop_back()        删除c中尾元素,若c为空,则函数行为未定义,函数返回void

c.pop_front()      删除c中首元素,若c为空,则函数行为未定义,函数返回void

c.erase(p)       删除迭代器p所指的元素,返回以指向被删除元素之后的迭代器

                                              若p指向尾元素,则返回尾后迭代器。若p是尾后迭代器,则函数的行为未定义

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

                                              若e本身就是尾后迭代器,则函数也返回尾后迭代器

c.clear()           删除c中的所以元素,返回void
 

4、改变容器大小

c.resize(n)  调整c的大小为n个元素,如果n<c.size()多余元素被丢弃,若小于需要添加初始化的新元素。

5、迭代器失效问题

向容器内添加、删除元素都会导致所有指向容器的迭代器、引用和指针失效。

添加元素:

vector和string:插入位置之前元素的迭代器、引用和指针仍然有效,之后的失效

deque:插入到除了首尾位置之外的任何位置都会失效

删除元素:

vector和string:插入位置之前元素的迭代器、引用和指针仍然有效,之后的失效

总结:

1、但是对于list来说,仍然有效。

2、需要保证每次改变容器操作后都正确的重新定位迭代器。

vector<int> vi = { 1, 2, 3, 5, 6 };
auto iter = vi.begin();
while (iter != iter.end()){
	if (*iter % 2)//奇数
	{
		iter = vi.insert(iter, *iter);//在iter向前插入现有数值,然后iter指向新的位置
		iter += 2;//需要跳过新位置和之前位置,到下一个数值
	}
	else{//偶数
		iter = vi.erase(iter);//删除后指向下一位置
	}
}

iter=...就是对于新位置的一种更新。

3、循环中重新调用end()

因为end()是会变化的。


关联容器

      关联容器支持通过键值来高效的查找和读取元素,这是它和顺序容器最大的区别。两种基本的关联容器类型是map和set。map的元素以键-值对的形式组织:键用作元素在map中的索引,而值则表示所存储和读取的数据。set仅包含一个键,并有效的支持关于某个键是否存在的查询。

一.pair类型

pair类似于容器,也是一个模板。定义在头文件utility中,数据成员是public的,两个成员命名为first 和 second .

pair<T1, T2>  p;
pair<T1, T2>  p(v1, v2);
p.first//访问成员对象
p.second
p=make_pair(v1, v2);//创建新的pair对象

因为pair的声明比较长,如果需要多次用到,可以使用别名:


typedef pair<string,int> Book;
Book book1;
Book book2;

二.map类型

map是键-值对的集合。关键字起到索引的作用,值则表示与索引相关联的数据。

map就是存储pair类型对象的容器,模板。

1.map对象的定义

#include<map>
map<int,string> map1;
map<int,string> map2(map1);
map<int,string> map3(map1.begin(),map1.end());
    

2.访问map容器的元素

在map容器中,包含着三种类型的对象,分别是key_type,mapped_type,value_type,分别表示,键的数据类型,值得数据类型,map数据元素pair的数据类型。key-value , mapped_type是pair元素,由于不能改变关键字,具体为pair <const key_type, mapped_type>

map<int,string> map1;
//定义迭代器类型
map<int,string>::iterator iter=map1.begin();
//可以通过first,second成员访问键和值
//map<int,string>::key_type,键不可以更改
cout<<iter->first;
//map<int,string>::mapped_type,可以更改。
cout<iter->second+1;

3、通过insert添加元素

m.insert(e)                           
m.insert(beg,end)                                
m.insert(iter,e)   


map<string ,int> map1;
//方法一
map1.insert(map<string,int>::value_type("one",1));

//方法二,使用make_pair
map1.insert(make_pair("two",2);

//方法三:也可以使用别名typtdef简略写法
typedef map<string,int>::value_type mapType;
map1.insert(mapType("threee",3));
      
//简单方法,列表初始化
map1.insert({world,1});

 map的insert返回值为pair<map<string,int>::iterator, bool>

 set的insert返回值为pair<set<int>::iterator, bool>

两部分:first成员是迭代器,指向具有给定关键字的元素。second是一个bool,指出元素是否插入(若已存在,返回false)

map<string,int> word_count;
string word;
while(cin>>word){
  auto ret=word_count.insert({word,1});
  if(!ret.second)//如果不存在,要插入
     ++ret.first->second;//增加计数器
}

4、使用下标访问和添加元素

map使用下标和vector类似,返回的都是下标关联的值,但是map的下标是键而不是递增的数字。

map<string,int> map1;
map1["one"]=1;

①、判断map1是否存在one的键,得出不存在。

②、新建一个pair<string,int>对象。

③、将新建的对象插入map1中。

④、修改map1中one对应的值为1。


string key;
while(cin>>key)
{
     ++map1[key];
}

5、通过find,count查找元素

map中下标读取元素的缺点是当不存在该元素时会自动添加,有时这是我们不希望看到的。

m.count(k)               返回m中k出现次数
m.find(k)                如果m容器中存在按k索引的元素,则返回指向该元素的迭代器。

map<string,int> map1;

if(map1.count("one")==1)
   cout<<map1["one"];

map<string,int>::iterator iter=map1.find("one");
 
if(iter!=map1.end())
  cout<<iter->second;

三.set类型

set遇到相同的值只保存一个.

与不能改变map的关键字一样,set 的关键字也是const 的,不能改变。

#include <iostream>
#include <set>
using namespace std;
//通过容器vector生成的类ivec
vector<int> ivec;
for(vector<int>::size_type  i=0;i!=10;++i)
{
    ivec.push_back(i);
    ivec.push_back(i);
}

//用ivec初始化set
set<int>  iset(ivec.begin(),ivec.end());
cout<<ivec.size()<<endl;        //输出20
cout<<iset.size()<<end;         //输出10

四.multimap和multiset的使用

它们的每个键都可以对应多个实例。由于一个键对应多个实例,因此,不能使用下标反问他们的元素,除此之外,其他操作和mapset没有任何不同。

添加元素

multimap<string,int> map1;
map1.insert(make_pair("one",1));
map1.insert(make_pair("one",2));

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值