STL容器大总结区分(上)

如图所示 ,按大小说明其重要性

那就先说两个最重要的:

vector---数组              list-----链表

vector 基本概念
功能:
vector 数据结构和 数组非常 相似 ,也称为 单端数组
vector 与普通数组区别:
不同之处在于数组是静态空间,而 vector 可以 动态扩展
动态扩展:
并不是在原空间之后续接新空间,而是找更大的内存空间 ,然后将原数据 拷贝 新空间,释放原空间
vector 容器的迭代器是支持 随机访问 的迭代器

list 链表  
有数据域和指针域
优点 1可以对任意位置进行快速插入和删除元素    2动态分配存储 
缺点 容器遍历速度慢,因为要通过指针域来找元素,比数组慢。占用的空间也比数组大,因为有数据域和指针域。
STL中的链表是一个双向循环链表
支持头部和尾部的插入删除 
链表的存储方式不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器 


list有一个重要的性质,插入操作和删除操作都不会造成原有list迭代器的失效,这在vector是不成立的
因为,vector如果满了,就会开辟新内存空间,原有迭代器会失效 
可以想象vector是一排连接起来的箱子,list是独立的箱子,放哪都不会影响内存

说到这,插入一个知识点
vector                                                随机访问迭代器
deque                                                随机访问迭代器
list                                                    双向迭代器
set/multiset                                                    双向迭代器
map/multimap                                                      双向迭代器
stack                                                不支持迭代器
queue                                                        不支持

好,言归正传

先从构造函数开始讲,这几类的方式都大差不差,包括构造时候和赋值和删除插入时

先从构造时候说

在list和vector都有四种方式构造函数

默认构造 无参构造 

还可通过区间的方式进行构造

n个elem方式构造

拷贝构造

实例说明

vector的

void test01(){vector<int> v1;//默认构造 无参构造     for(int i=0;i<=10;i++){v1.push_back(i);} 						//掌握好第一个和第四个  构造完后面赋值就好 printVector(v1);//还可通过区间的方式进行构造vector<int> v2(v1.begin(),v1.end()) ;printVector(v2);//n个elem方式构造vector<int> v3(10,100);//十个100 printVector(v3);//拷贝构造vector<int> v4(v3);printVector(v4); 
}

list的

void test01(){list<int> l1;//添加数据 l1.push_back(10);l1.push_back(20);l1.push_back(30);l1.push_back(40);//遍历容器printList(l1); //区间方式构造list<int>L2(l1.begin(),l1.end());printList(L2); //拷贝构造list<int>L3(L2);printList(L3);//n个elemlist<int>l4(10,1000);printList(l4); 
} 

不一样的只是容器名,其他几个也大差不差,一会也一并说了其相似和差异

继续说  赋值方式   两个一样,都是四种

默认赋值

赋值    operator=

assign

assign    n个elem方式赋值

//vector赋值
void test01(){vector<int> v1;//默认赋值 for(int i=0;i<10;i++){v1.push_back(i);}printVector(v1);//赋值	operator=vector<int> v2; v2=v1;printVector(v2);//assignvector<int> v3;v3.assign(v1.begin(),v1.end());printVector(v3);//assign	n个elem方式赋值vector<int> v4;v4.assign(10,100);printVector(v4); } 

list赋值

void test01(){list<int>L1;L1.push_back(10);L1.push_back(20);L1.push_back(30);L1.push_back(40);printList(L1);list<int>L2;L2=L1;//operator=赋值printList(L2);list<int>L3;L3.assign(L2.begin(),L2.end()) ;printList(L3);list<int>L4;L4.assign(10,100);printList(L4);
} 

vector和list容器(只有vec)大小

vector和list大小操作

这几个接口

empty size capacity resize

capacity        list么有

vector

void test01(){vector<int> v1;for(int i=0;i<10;i++){v1.push_back(i);}printVector(v1);if(v1.empty())//为真 为空{cout<<"v1为空"<<endl;} else{cout<<"v1不为空"<<endl;cout<<"v1的容量为: "<<v1.capacity()<<endl;cout<<"v1的大小为"<<v1.size()<<endl;//容量永远大于大小 }//重新指定大小v1.resize(15,100);//利用重载版本,可以指定默认填充值,参数2 printVector(v1);//如果重新指定的比原来长了,默认用0来填充v1.resize(5);//重新指定的比原来短了,超出的部分会删除掉 printVector(v1); cout<<"v1的容量为: "<<v1.capacity()<<endl;//容量还是没变 
}

list

void test01(){list<int>L1;L1.push_back(10);L1.push_back(20);L1.push_back(30);L1.push_back(40);printList(L1);if(L1.empty()){cout<<"L1为空"<<endl;}else{cout<<"L1不为空"<<endl;cout<<"L1元素个数"<<L1.size()<<endl;}//重新指定大小L1.resize(10,10000);
//	L1.resize(10);//后面默认用0填充 printList(L1);L1.resize(2);printList(L1);//其他删除 } 

插入和删除

尾删和尾插两个都有        因为在随机访问迭代器中在头部上处理的是下一个容器deque,这里暂且不表   要分清front和x.begin()所表示什么

尾插    v1.push_back(40);     L.push_back(10);

尾删  v1.pop_back();                    L.pop_back();

insert一样

vector

	//插入	第一个参数是 迭代器 v1.insert(v1.begin(),100);printVector(v1); v1.insert(v1.end(),200);printVector(v1);v1.insert(v1.begin(),2,1000);printVector(v1);//加了两个1000

list

//insert插入list<int>::iterator it=L.begin();L.insert(++L.begin(),1000);//it灵活运用 printList(L);L.insert(L.end(),2,9);printList(L);

接下来说删除,删除这稍微不一样

通常就是erase()和clear()   list加了一个remove()

	//删除	参数也是 迭代器 v1.erase(v1.begin()) ;printVector(v1);//	v1.erase(v1.begin(),v1.end());//清除区间		删除第三个2到4 v1.clear() ;//也是清除区间 printVector(v1);

list

	//删除it=L.begin();L.erase(it);printList(L);//删了200//移除L.push_back(10000);L.push_back(10000);L.push_back(10000);printList(L);L.remove(10000);//删除所有匹配的值 printList(L);//删掉了 //清空L.clear();printList(L);//多了一个空行 

    L.remove(10000);//删除所有匹配的值 
    printList(L);//删掉了 

删除的是所有remove里面的数(1000)

数据存储

vector可以用[]和at()访问        和获取第一个元素v1.front()    获取最后一个v1.back()

void test01(){vector<int> v1;for(int i=0;i<10;i++){v1.push_back(i);}//利用中括号方式来访问数组中的元素 for(int i=0;i<v1.size();i++){cout<<v1[i]<<" ";}cout<<endl;//	和string同理 利用at方式访问元素for(int i=0;i<v1.size();i++){cout<<v1.at(i)<<"  ";} cout<<endl;//获取第一个元素cout<<"第一个元素为:"<<v1.front()<<endl;//获取最后一个cout<<"最后一个元素"<<v1.back()<<endl; 
} 

list不支持at()和[],因为链表不是连续空间    而且链表也不支持随机访问,双向迭代器只能前移和后移              这句说的太好了           防止忘记,让我们再次回顾list优点缺点

优点 1可以对任意位置进行快速插入和删除元素    2动态分配存储 
缺点 容器遍历速度慢,因为要通过指针域来找元素,比数组慢。占用的空间也比数组大,因为有数据域和指针域。

void test01(){list<int>L1;L1.push_back(10);L1.push_back(20);L1.push_back(30);L1.push_back(40);//	L1[0]是错误的L.at(0)错误cout<<"第一个元素为"<<L1.front()<<endl;cout<<"最后一个元素为"<<L1.back()<<endl;//验证迭代器是不支持随机访问的list<int>::iterator it=L1.begin();it++;//正确	支持双向it--; 
//	it+=1;报错  其不支持随机访问  可以用加法来判断是否支持随机访问
//或者写it--看其是否为单向 cout<<*it; } 

这一段着重看,学思想  

 //验证迭代器是不支持随机访问的
    list<int>::iterator it=L1.begin();
    it++;//正确    支持双向
    it--; 
//    it+=1;报错  其不支持随机访问  可以用加法来判断是否支持随机访问
//或者写it--看其是否为单向 
    cout<<*it;

  swap()

两个都有swap()属性,但这里list用reverse来表示
vector

void test01(){vector<int> v1;for(int i=0;i<10;i++){v1.push_back(i);}cout<<"交换前"<<endl; printVector(v1);vector<int> v2;for(int i=10;i>0;i--){v2.push_back(i);}printVector(v2);cout<<"交换后"<<endl;v1.swap(v2);printVector(v1);printVector(v2);
}

vector        swap()实际用途

//巧用swap()可以收缩内存空间
void test02(){vector<int> v;for(int i=0;i<100000;i++){v.push_back(i);}cout<<"v的容量为:"<<v.capacity()<<endl;cout<<"v的大小为"<<v.size()<<endl;v.resize(3);//大小变小 cout<<"v的容量为:"<<v.capacity()<<endl;cout<<"v的大小为"<<v.size()<<endl;//内存变小了 但是容量没变//巧用swap收缩内存vector<int>(v).swap(v);cout<<"v的容量为:"<<v.capacity()<<endl;cout<<"v的大小为"<<v.size()<<endl; //容量和内存都小了//解析  其先初用 v创建了一个匿名对象vector<int>(v) 其内存和大小都是3 //然后swap 指针方向交换 所以v内存和大小都为3//匿名对象指向的大空间 当前行执行完立即回收,所以不存在占空间 
} 

 

list

void test01(){//反转 list<int>L1;L1.push_back(20);L1.push_back(10);L1.push_back(50);L1.push_back(40);L1.push_back(30);printList(L1);cout<<"反转后"<<endl;L1.reverse();printList(L1);
} 

 

接下来是两个独有属性

 list排序

//排序
void test02(){list<int>L1;L1.push_back(20);L1.push_back(10);L1.push_back(50);L1.push_back(40);L1.push_back(30);cout<<"排序前"<<endl;printList(L1);
//	sort(L1.begin(),L1.end());报错
//原因所有不支持随机访问迭代器的容器,不可以用标准算法
//不支持随机访问的迭代器,内部会提供对应的一些算法cout<<"升序排列"<<endl;L1.sort();//运行成功     默认从小到大 printList(L1);cout<<"降序排列"<<endl;	L1.sort(myCompare);//提供函数改变sort顺序 printList(L1);
}

重点是

    sort(L1.begin(),L1.end());报错
     原因所有不支持随机访问迭代器的容器,不可以用标准算法
     不支持随机访问的迭代器,内部会提供对应的一些算法

所以    L1.sort();//运行成功     默认从小到大 

vector预留空间

统计开辟内存次数                        用reserve先开辟内存就不用后面再开辟了

#include <iostream>
#include <vector>
#include<string>
using namespace std;
//reserve(int len)//容器预留len个元素长度,预留位置不初始化,元素不可访问void test01(){vector<int> v;//利用reserve预留空间v.reserve(100000); //这回运行结果为0 int num=0;//统计开辟内存次数int*p=NULL; for(int i=0;i<100000;i++){v.push_back(i);if(p!=&v[0]){p=&v[0];//循环找第一个内存  num++;}}	//vector可动态拓展 是找一块更大的空间 把原有的数据拷贝新空间,释放原空间cout<<num;
} 
int main()
{test01();system("pause");
}

两个print函数

void printVector(vector<int> &v){
    for(vector<int>::iterator it=v.begin();it!=v.end();it++){
        cout<<*it<<" ";
    }
    cout<<endl;
}

如此看来两个除了容器名不同,输出其他都相同

void printList(list<int> &L){
    for(list<int>::iterator it=L.begin();it!=L.end();it++){
        cout<<*it<<" ";
    }
    cout<<endl;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/435004.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HarmonyOS漫谈---套壳安卓还是套壳苹果?HarmonyOS更像谁?

2020年以前华为手机的操作系统是EMUI,这个是在Android基础上扩展而来的,版本和android几乎一致,和市面上其它android手机厂家搭载的系统并无本质不同 2019年5月16日,美国针对华为发起了第一轮制裁。8月华为发布了HarmonyOS1.0,此时还只是主要在IOT设备上使用,智慧屏成为…

贝叶斯增量式跨域适应:少样本 + 跨模态学习 + 知识保留和推断【fundus + OCT】,做视网膜病变

贝叶斯深度学习&#xff1a;增量式少样本学习跨域适应 贝叶斯多目标函数 跨模态学习 fundus OCT&#xff0c;做视网膜病变 核心思想设计网络&#xff1a;寻找分类模型、损失函数实验结果混淆矩阵与注意力图评估 总结 核心思想 论文&#xff1a;https://arxiv.org/pdf/2110.…

paddlepaddle在执行loss.item()的时候,报错an illegal memory access was encountered.

遇到的问题是“an illegal memory access was encountered”&#xff0c;这是一个常见的内存错误。 首先&#xff0c;要确保你的代码中没有其他明显的内存错误&#xff0c;例如&#xff1a; 确保你没有试图访问超出数组边界的元素。确保你没有试图释放已经释放的内存。确保你没…

尚无忧球馆助教系统源码,助教小程序源码,助教源码,陪练系统源码

特色功能&#xff1a; 不同助教服务类型选择 助教申请&#xff0c;接单&#xff0c;陪练师入住&#xff0c;赚取外快 线下场馆入住 设置自己服务 城市代理 分销商入住 优惠券 技术栈&#xff1a;前端uniapp后端thinkphp 独立全开源

C#学习(十一)——Array和Collection

一、集合 集合重要且常用 孤立的数据是没有意义的&#xff0c;集合可以作为大量数据的处理&#xff0c;可进行数据的搜索、迭代、添加、删除。 C#中&#xff0c;所有集合都必须实现ICollection接口&#xff08;数组Array除外&#xff09; 集合说明Array数组&#xff0c;固定长…

网络安全02--负载均衡下的webshell连接

目录 一、环境准备 1.1ubentu虚拟机一台&#xff0c;docker环境&#xff0c;蚁剑 1.2环境压缩包&#xff08;文件已上传资源&#xff09;&#xff1a; 二、开始复原 2.1上传ubentu&#xff1a; 2.2解压缩 2.3版本20没有docker-compose手动下载&#xff0c;包已上传资源 …

第2章-神经网络的数学基础——python深度学习

第2章 神经网络的数学基础 2.1 初识神经网络 我们来看一个具体的神经网络示例&#xff0c;使用 Python 的 Keras 库 来学习手写数字分类。 我们这里要解决的问题是&#xff0c; 将手写数字的灰度图像&#xff08;28 像素28 像素&#xff09;划分到 10 个类别 中&#xff08;0…

32GPIO输入LED闪烁蜂鸣器

一.GPIO简介 所有的GPIO都挂载到APB2上&#xff0c;每个GPIO有&#xff11;&#xff16;个引脚 内核可以通过APB&#xff12;对寄存器进行读写&#xff0c;寄存器都是32位的&#xff0c;但每个引脚端口只有&#xff11;&#xff16;位 驱动器用于增加信号的驱动能力 二.具体…

数据结构-线性表

文章目录 数据结构—线性表1.线性表的定义和基本操作线性表的定义线性表的特点线性表的基本操作 2.线性表的顺序存储和链式存储表示顺序存储链式存储单链表循环链表双向链表 数据结构—线性表 1.线性表的定义和基本操作 线性表的定义 定义&#xff1a;线性表是具有相同数据类…

SpringSecurity(16)——OAuth2客户端授权模式

工作流程 基本使用 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId><version>2.3.12.RELEASE</version> </dependency> <dependency><groupId>…

Android发展历程及安装

目录 发展历程 下载网址 安装过程 发展历程 安卓基于Linux内核&#xff0c;Linux内核相当于房屋的地基 开源不等于免费&#xff0c;不能商用 安卓一般每半年小更新&#xff0c;一年大更新 对应API相当于别名 现在安卓安全性越来越高&#xff0c;性能越来越快&#xff0c…

LeNet跟LeNet5详解

1 LeNet结构 主要是为了手写数字识别 具体结构讲解&#xff1a;从图中例子可得 1 先传入一个灰度图像尺寸为1x28x28&#xff0c;通道数为1&#xff0c;尺寸为28x28的灰度图像 2 第一层5x5卷积&#xff0c;经过公式 输入图像尺寸-卷积核尺寸2padding/步长1&#xff0c;&#…