C++ 顺序容器

本文详细介绍了C++中的顺序容器,包括vector、list、deque、forward_list、array和string的特点与性能差异。重点阐述了在不同场景下如何选择合适的容器,以及容器的常用操作,如插入、删除、访问元素等。此外,还提到了forward_list的特殊性和容器适配器stack、queue、priority_queue的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、各个顺序容器性能差异主要体现在一下两个方面:

1.在容器中任意位置添加和删除元素的代价

2.随机访问容器中元素的代价

vector、list、deque、forward_list、array、string

vector是可变大小数组,支持快速随机访问,在尾部插入和删除元素较为方便

list是双向链表,只支持双向顺序访问,在任意位置插入和删除元素都比较方便

deque是双端队列,支持快速随机访问,在头尾位置插入和删除元素较为方便

forward_list是单向链表,只支持单向顺序访问。在任意位置插入和删除元素都比较方便

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

string是专门用于保存char的vector,支持快速随机访问,在尾部插入和删除元素较为方便


对于vector和string由于是在内存中连续存储,所以可以根据下标来计算地址进行访问,在中间删去和添加某一元素,其后面位置都要进行移动以保持连续存储。

list、forward_list主要用于解决在容器任意位置插入和删除元素代价大的问题,但其后果是访问任一元素较为麻烦,需要对整个容器进行遍历后才可以,并且其额外内存开销较大。

deque是一种较为复杂的数据结构,在中间位置添加和删除元素代价较高,但在两端添加和删除元素较为方便,速度与list和forward_list较为接近。

二、关于容器的选用基本原则:

1.除非有很好的理由选用其他容器,否则使用vector

2.容器元素很多,且对空间开销比较敏感,则不要使用list和forward_list

3.如果要求随机访问,则使用vector或string,如果要求在中间位置插入和删除方便,则使用list和forward_list

4.只在头尾位置插入和删除元素,使用deque

5.如果既要求能随机访问容器中元素,又要求可以在任意位置添加和删除元素,那就要看在工程中占主导地位的是随机访问还是任意位置插入、删除(看二者哪个操作需要的更更加频繁),视情况选择vector或者list

三、容器操作层次

几乎可以在容器中保存所有类型的数据

如果出现此种情况,nodefault为无构造函数类型

vector<nodefault> a(10, init);//正确

vector<nodefault> b(10);//错误

1、对所有容器都通用的操作

iterator    迭代器

const_iterator  只读迭代器

size_type     无符号整数类型 //足够存放任何容器对象的大小 例如:string::type

difference_type   带符号整数类型

value_type    元素类型 

reference      元素左值类型   //元素类型的一个引用

const_referemce   元素const左值类型

2、仅仅适用于顺序容器、适用于关联容器、适用于无序容器

3、只适用于一小部分容器

四、容器定义与初始化

1、C c;

C c1(c2);

C c {};

C c (a,b);//ab均为迭代器

C c(n,t);

C c(n);


#include<iostream>
#include<vector>
#include<list>
#include<string>
using namespace std;
int main()
{
list<string> a{ "aaa", "bbb", "ccc" };
list<string>::iterator it = a.begin();
it++;
it++;
list<string> b(a.begin(), it);
for (list<string>::iterator it1 = b.begin(); it1 != b.end(); it1++)
{
cout << *it1 << endl;
}
return 0;
}

输出结果为:aaa bbb

2、array定义与初始化稍有不同 ,因为array长度固定

array<int,10> 必须加上10

与内置数组区别:可以直接进行拷贝

int a[] = {0,1,2,3};

int b[] = a//错误错误

array<int,3>  a= {1,2,3};

array<int,3> b = a; //正确

五、赋值和swap

1、assign用法:

list<string> names;

vector<const char*> oldstyle;

names.assign(oldstyle.begin(),oldstyle.end()); //注意:容器类型可以不同


list<string> slist(1);

slist.assign(10,"hhhh");

2、swap用法

交换两个相同类型的容器的内容

vector<string>sevc1(10);
vector<string>sevc2(24);
swap(sevc1, sevc2);

调用swap之后,元素本身并未交换,只是交换了整个容器的数据结构

迭代器、指针、引用等仍然指向原来的元素 比如指针a原来指向sevc1[3]  现在指向sevc2[3]

string有所不同,对string容器调用swap后,这些都将失效

而对array来说,则会真正交换二者的元素。

3、容器大小操作

容器关系运算符比较大小、实际为容器中元素的逐个比较

六、顺序容器操作

1、添加元素

push_back除去array与forward_list都支持  本质是在容器尾部创建了一个新的元素,容器的size增大了1

对容器进行初始化实际上放入容器的是元素的一个拷贝,而不是元素本身


push_front  deque、list、forward_list支持


insert提供了更一般的添加功能,允许我们在容器任意位置进行元素添加(用该方法对所有顺序容器都是有效的,只是相对来说,vector、string、deque更耗时)

slist.insert(iter,"aaa");//iter为容器类型的迭代器

slist.insert(slist.end(),10,"aaa");

insert返回值为指向刚刚插入的元素的迭代器


emplace_front、emplace、emplace_back

与push、insert区别:如果容器类型不是内置类型的话 前者将参数传递给构造函数,然后函数实现在容器末尾添加新构造元素;后者要进行赋值、移动等。

2、访问元素

front与back成员函数分别返回首元素和尾元素的引用

注意与begin和end的区别

begin函数:

函数原型:

iterator begin();

const_iterator begin();

功能:

返回一个当前vector容器中起始元素的迭代器。

 

end函数:

函数原型:

iterator end();

const_iterator end();

功能:

返回一个当前vector容器中末尾元素的迭代器。

 

front函数:

函数原型:

reference front();

const_reference front();

功能:

返回当前vector容器中起始元素的引用。

 

back函数:

函数原型:

reference back();

const_reference back();

功能:

返回当前vector容器中末尾元素的引用。

at(n)函数仅仅适用于string、vector、deque、array  如果下标越界,at()会抛出异常

3、删除元素

pop_back()

pop_front()

erase(p)//p为迭代器  删除p指向的元素 函数返回值为指向删除元素下一个元素的迭代器

erase(b,e)//删除b、e所指定范围内元素 

clear()

七、特殊的forward_list

forward_list<int> a{ 0, 1, 2, 3, 4, 5, 6, 7, 8 };
auto p1 = a.before_begin();
auto p2 = a.begin();
while (p2 != a.end())
{
if (*p2 % 2 == 0)
{
p2 = a.erase_after(p1);
}
else
{
p1 = p2;
++p2;
}
}

八、容器适配器

三个容器适配器:

stack、queue、priority_queue

一个适配器是一种机制,能使某种事物的行为看起来像另外一种事物一样

size_type

value_type

container_type

A a;

A a(c);

a.empty();

a.size();

swap(a,b);

a.swap(b);

两个构造函数

默认构造函数接受一个空对象,接受一个容器的构造函数拷贝该容器来初始化适配器。

deque<int> deq;

stack<int> stk(deq);



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值