C++中容器

  • 容器是什么?
  • string容器
    • 构造函数
    • 常见函数
  • vector容器
    • 与array的区别
    • 构造函数
    • 常见函数
    • 迭代器
      • 迭代器是什么?
  • deque容器
    • 实现原理
    • 常见函数
  • stack容器 栈
    • 常见函数
  • queue容器
    • 常见函数
  • list容器 链表
    • 链表的概念
    • list容器的迭代器
    • 常见函数
  • set/multiset容器
    • 二叉树
    • 常见函数
  • map/multimap容器
    • map和set的**区别**是:

容器是什么?

几乎可以说,任何特定的数据结构都是为了实现某种特定的算法。STL容器就是将运用最广泛的一些数据结构实现出来。
常用的数据结构:数组(array) , 链表(list), tree(树)栈(stack),** 队列(queue)**, 集合(set),映射表(map), 根据数据在容器中的排列特性,这些数据分为序列式容器和关联式容器两种。

  • 序列容器强调值的排序,每个元素有着固定的位置,比如vector,deque,list
  • 关联容器一般是树状结构,方便查找,强调键值对。键起到索引作用,比如map,set

string容器

c语言中char风格字符串(以空字符为结尾的字符组难以掌握),不适合大型程序的开发,所以在头文件<string>内定义了一种string类。与char相比,string是个类而char是个指针,封装了更多的方法,不用考虑内存的释放和越界。

构造函数

string();//创建一个空的字符串 例如: string str;
string(const string& str);//使用一个string对象初始化另一个string对象
string(const char* s);//使用字符串s初始化
string(int n, char c);//使用n个字符c初始化
string s(int beg,int end) //以区间beg;end(不包含end)内的字符作为字符串s的初值

常见函数

大小容量函数 作用
size(),length() 返回字符串长度
max_size() 返回当前字符串最多能包含的字符数
capacity() 重新分配内存之前 string所能包含的最大字符数
reserve() 为当前的string重新分配内存,参数为分配内存的大小
元素存取函数 作用
at(),[] 索引不会检查长度在str[str.length()]依然有效,返回值为’\0’
比较函数 作用
>,>=,<,<=,==,!= 按照字典顺序比较
compare() 返回0则相等,支持多参数
更改内容函数 作用
= 赋值
compare() 返回0则相等,支持多参数
assign(str,begin,end) 返回str[begin:end]的值
append() 往后面加字符
push_back() 加单个字符太常见了吧
insert(index,str) 索引index的位置加一个str
replace(1,2,str) 从索引为1开始后两个换成str
erase(7,5) 索引7的位置删除5个,如果形参2没有,默认从参数1索引后面删光
substr(5,6) 提取5到6的子串
find 查找
find_first_of 反 查找包含子串中的任何字符,返回第一个位置
find_first_not_of 查找不包含子串中的任何字符,返回第一个位置
find_last_of 查找包含子串中的任何字符,返回最后一个位置
find_last_not_of 查找不包含子串中的任何字符,返回最后一个位置

vector容器

与array的区别

vector的数据安排以及操作方式,与array非常相似,两者的唯一差别在于空间的运用的灵活性。
与array的区别:使用的 是动态空间,就算内容变动也会自动重新分配内存。两者在内存空间都是连续的内存空间。
动态增长的原理:如果空间不足会申请更大的内存空间,会拷贝到新空间,释放旧空间。

构造函数

vector<T> v; //采用模板实现类实现,默认构造函数
vector(v.begin(), v.end());//将v[begin(), end())区间中的元素拷贝给本身。
vector(n, elem);//复制构造拷贝。
vector(const vector &vec);//拷贝构造。
vector<int> nVec(5,-1);//参数1是vector里面的数量1,参数是赋值
vector<string>str_vec{'a','b'}//注意“()”,“{}”的区别,()是函数,参数里面的是函数。因为是构造函数的形参。一般情况下创建空的然后往里面+数,类似于python中的append()。
std::vector<int>nVec;
for(int i = 0; i<5;++i)nVec.push_back(i);

常见函数

函数 作用
insert() 添加元素(函数重载过多次,可以看下面的应用)
push_back() 从后面加一个,效率高,不需要换地址的
pop_back() 删除
size() 大小操作是否为空
resize() 默认值填充,多的直接删除
capacity() 观察容量
vector<int>list{10,9,8,7};
list.insert(pos,num); // 在pos位置插入元素num
list.insert(pos,n,num);   // 在pos位置插入n个元素num重复性数据
list.insert(pos,beg,end);  // 在pos位置插入区间为[beg,end)的元素,自己的元素
c.erase(p);      // 删除迭代器p所指定的元素,返回一个指向被删除元素之后的迭代器。
c.erase(begin,end);   // 删除b,e所指定范围内的元素,返回一个指向被删除元素之后的迭代器。
c.clear();       // 删除所有元素

vector添加元素时会内存自动增长,删除的时候会自动回收吗?
不会!下面分享一个用于节约内存的方法,利用交换swap函数重新分配内存。

vector<int>v;
for (int i = 0;i <100000;++i)
{v.push_back(i)}v.resize(10); //缩小内存空间vector<int>(v).swap(v);

迭代器

迭代器是什么?

迭代器是一种抽象的设计理念,通过迭代器可以在不了解容器内部原理的情况下遍历容器。除此之外,STL 中迭代器一个最重要的作用就是作为容器与 STL 算法的粘结剂,只要容器提供迭代器的接口,同一套算法代码可以利用在完全不同的容器中,这是抽象思想的经典应用。
迭代器和C++的指针非常类似,它指向容器中的某个元素,如果需要也可以对容器的值读/写操作。

  • Input itertor (输入迭代器)只读;只支持自增运算
  • Output itertor(输出迭代器)只写;只支持自增运算
  • Forward itertor(前向迭代器)读写;只支持自增运算forward_list,unordered_map / unordered_multimap,unordered_set / unordered_multiset
  • Bidirectional itertor(双向迭代器)读写;支持自增和自减 list set/multiset,map/multimap
  • Random access itertor(随机访问迭代器)读写;支持完整迭代器算数运算 array,vecor,deque
  • stackqueue不支持迭代器

vector迭代代码实现:

#include <iostream>
#include<vector>using namespace std;int main(){vector<int> v{1,2,3,4,5,6};vector<int>::iterator it = v.begin()for(;*it !=v.end();it++){cout << *it <<'';}return 0;}

deque容器

vector容器是单向开口的连续内存空间,deque则是一种双向开口的连续线性空间。所谓的双向开口,意思是可以在头尾两端分别做元素的插入和删除操作,当然,vector容器也可以在头尾两端插入元素,但是在其头部操作效率奇差,需要开辟一块新的内存,无法被接受。
deque是 一种 动态分段连续空间 组成的,

实现原理

deque容器是连续的空间,至少逻辑上看来如此,连续现行空间总是令我们联想到array和vector,array无法成长,vector虽可成长,却只能向尾端成长,而且其成长其实是一个假象,事实上(1) 申请更大空间 (2)原数据复制新空间 (3)释放原空间 三步骤,如果不是vector每次配置新的空间时都留有余裕,其成长假象所带来的代价是非常昂贵的。


deque是由一段一段的定量的连续空间构成。一旦有必要在deque前端或者尾端增加新的空间,便配置一段连续定量的空间,串接在deque的头端或者尾端。Deque最大的工作就是维护这些分段连续的内存空间的整体性的假象,并提供随机存取的接口,避开了重新配置空间,复制,释放的轮回,代价就是复杂的迭代器架构。
既然deque是分段连续内存空间,那么就必须有中央控制,维持整体连续的假象,数据结构的设计及迭代器的前进后退操作颇为繁琐。Deque代码的实现远比vector或list都多得多。

//二叉树的节点
class Linknode
{public:linknode(); //构造函数int data;Linknode* left; //左节点Linknode* right;  //右节点
};
Linknode::linknode()
{left =NULL;right =Null;
}
class Tree
{Linknode* root; //创建二叉树的根}

常见函数

构造函数 作用
dequie<T> deq 默认构造函数
deque(const deque &deq) 拷贝构造函数
deque(beg, end) 拷贝函数,构造函数将[beg, end)区间中的元素拷贝给本身
deque(n, elem) 构造函数将n个elem拷贝给本身
deque赋值操作 作用
assign(beg, end) 将[beg, end)区间中的数据拷贝赋值给本身
assign(n, elem) 将n个elem的值赋给本身
deque& operator=(const deque &deq) 重载=操作符
swap(deq) 交换元素
deque大小操作 作用
deque.size() 返回deque中元素的个数
deque.empty() 返回容器中为空否为真
deque.resize(num) 重新指定容器的长度为num,若容器变长,则以默认值填充新位置。如果容器变短,则末尾 超出容器长度的元素被删除。
deque.resize(num, elem) 若分配的内存大于原先的,则用elem填充
deque双端操作 作用
push_back(elem) 在容器尾部添加elem
push_front(elem) 在容器头部添加elem
pop_back(elem) 在容器尾部删除一个元素
pop_front(elem) 在容器头部删除一个元素
deque数据存取 作用
deq(idx) 返回索引idx所指的数据,如果idx越界,抛出out_of_range。
front() 返回容器第一个值
back() 返回容器最后一个值
deque插入 作用
insert(pos,elem) 在pos位置插入一个elem元素的拷贝,返回新数据的位置
insert(pos,n,elem) 在pos位置插入n个elem数据,无返回值
insert(pos,beg,end) 在pos位置插入[beg,end)区间的数据,无返回值
deque删除操作 作用
clear() ` 移除容器的所有数据
erase(beg,end) 删除[beg,end)区间的数据,返回下一个数据的位置
erase(pos) 删除pos位置的数据,返回下一个数据的位置

stack容器 栈

先进后出的容器,只有一个入口和出口,允许新增元素移除元素,取得最顶端元素,但是没有办法获取除了最顶端元素之外的元素,不允许有 遍历 行为和 迭代 行为!

常见函数

API 作用
push(elem) 向容器添加elem
pop() 移除容器第一个元素(栈顶)
top() 返回栈顶元素
empty() 判断是否为孔
size() 返回大小

queue容器

queue是一种先进先出(First In First Out,FIFO)的数据结构,它有两个出口,queue容器允许从一端新增元素,从另一端移除元素。与栈·一样没有迭代器

常见函数

API 作用
push(elem) 向容器添加elem
pop() 移除容器第一个元素(栈顶)
back() 返回最后一个元素
front() 返回第一个元素
empty() 判断是否为孔
size() 返回大小

list容器 链表

链表的概念

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。
list和vector是最常见的被使用的容器:

  • 采用动态存储分配,不会造成内存浪费和溢出
  • 链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素
  • 链表灵活,但是空间和时间额外耗费较大

    写成代码(随便写写,意思到了就行)就是:
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;
struct ListNode
{int data;ListNode* next;//结构体指针
};
void Listprintf(ListNode* phead)
{ListNode* cur=phead;while (cur != NULL){cout << cur->data << "->";cur = cur->next;}
}
void Listpushback(ListNode** pphead, int x)
{ListNode* newnode = new ListNode{ x,NULL };if (*pphead == NULL){*pphead = newnode;}else{ListNode* tail=  *pphead;while(tail->next != NULL){tail = tail->next;}tail->next = newnode;}
}
void test_1()
{ListNode* phead = NULL;Listpushback(&phead, 1);Listpushback(&phead, 2);Listpushback(&phead, 3); Listprintf(phead);
}
int main()
{test_1();return 0;
}

list容器的迭代器

list的迭代器不能像一些连续内存的容器中那样是指针,它需要的是利用递增递减可以前后捕捉每个节点的next和pre的能力。可以看上面代码如果指针没有指向null则会一直指向下一个Node的地址。

常见函数

构造函数 作用
list<T> lstT list采用采用模板类实现,对象的默认构造形式:
list(beg,end) 构造函数将[beg, end)区间中的元素拷贝给本身。
list(n,elem) 构造函数将n个elem拷贝给本身。
list(const list &lst) 拷贝构造函数
赋值函数 作用
push_back(elem) 在容器尾部加入一个元素
pop_back() 删除容器中最后一个元素
push_front(elem) 在容器开头插入一个元素
pop_front() 从容器开头移除第一个元素
insert(pos,elem) 在pos位置插elem元素的拷贝,返回新数据的位置。
insert(pos,n,elem) 在pos位置插入n个elem数据,无返回值。
insert(pos,beg,end) 在pos位置插入[beg,end)区间的数据,无返回值。
clear() 移除容器的所有数据
erase(beg,end) 删除[beg,end)区间的数据,返回下一个数据的位置。
erase(pos) 删除pos位置的数据,返回下一个数据的位置。
remove(elem) 删除容器中所有与elem值匹配的元素。
大小操作 作用
size() 返回容器中元素的个数
empty() 判断容器是否为空
resize(num) 重新指定容器的长度为num
resize(num, elem) 重新指定容器的长度为num
赋值操作 作用
assign(beg, end) 将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem) 将n个elem拷贝赋值给本身。
list& operator=(const list &lst) 重载等号操作符
swap(lst) 将lst与本身的元素互换。
reverse() 反转链表,比如lst包含1,3,5元素,运行此方法后,lst就包含5,3,1元素。
sort() list排序

set/multiset容器

set/multiset属于关联式容器,底层结构使用二叉树 实现的。它们的特点是:所有的元素的键值在插入时会自动被排序。不可以用迭代器改变set的值,因为如果动了其中一个值会影响整个的树的结构。而set与multiset容器的区别就是:set容器中不允许有重复的元素,而multiset允许容器中有重复的元素。

二叉树

树状图 是一种数据结构,它是由 n(n>=1)个有限结点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:
每个结点有零个或多个子结点;没有父结点的结点称为根结点;每一个非根结点有且只有一个父结点;除了根结点外,每个子结点可以分为多个不相交的子树。由于线性查找需要遍历全部数据,在数据量大的时候效率就非常低下,到底有多低,在数据库有几百万几千万以上数据量写过查询语句的就知道有索引和没索引的区别。

代码实现:

//二叉树的节点
class Linknode
{public:linknode(); //构造函数int data;Linknode* left; //左节点Linknode* right;  //右节点
};
Linknode::linknode()
{left =NULL;right =Null;
}
class Tree
{Linknode* root; //创建二叉树的根}

常见函数

构造函数 作用
set<T> st set默认构造函数:
mulitset<T> mst multiset默认构造函数:
set(const set &st) 拷贝构造函数
赋值函数 作用
set& operator=(const set &st) 重载等号操作符
swap(st) 交换两个集合容器
大小操作 作用
size() 返回容器中元素的数目
empty() 判断容器是否为空
插入和删除操作 作用
insert(elem) 在容器中插入元素。
clear() 清除所有元素
erase(pos) 删除pos迭代器所指的元素,返回下一个元素的迭代器。
erase(beg, end) 删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
erase(elem) 删除容器中值为elem的元素。
查找操作 作用
find(key) 查找键key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();
count(key) 查找键key的元素个数
lower_bound(keyElem) 返回第一个key>=keyElem元素的迭代器。
upper_bound(keyElem) 返回第一个key>keyElem元素的迭代器。
equal_range(keyElem) 返回容器中key与keyElem相等的上下限的两个迭代器。

map/multimap容器

map的特性是,所有元素都会根据元素的键值自动排序。
map所有的元素都是关联的,同时拥有实值和键值(key,value),第一元素被视为键值,第二元素被视为实值,map不允许两个元素有相同的键值.

  • map中的key是唯一的。集合中元素按照一定顺序排列。元素的插入按照规则插入我,所以不能指定插入位置。
  • map的底层是红黑树的变体,平衡二叉树。在插入操作、删除和检索上要比vector快很多。
  • map可以直接存取key所对应的value,支持[]操作符,如map[key]=value.
  • #include<map>
  • map支持唯一键值,每个键只能出现一次;而multimap中相同键可以出现多次。multimap不支持[]操作符

map和set的区别是:

Map对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。构造函数Map可以接受一个数组作为参数。
Set对象允许你存储任何类型的,无论是原始值或者是对象引用。它类似于数组,但是成员的值都是唯一的,没有重复的值。

#include<map>
#include<iostream>
using namespace std;
int main(void)
{multimap<int ,string> james;james.insert(pair<int,string>(3,'dog'));james.insert(pair<int,string>(4,'cat'));//遍历操作for (multimap<int,string>::iterator it = james.begin();it !=james.end();it++){cout <<(*it).first <<endl;}
}

C++ STL?看这篇就够啦。草履虫都能学会的STL教程!相关推荐

  1. tensorboard使用界面介绍以及使用方法(看这篇就够了,都有源码可以直接测试)

    0 总述 简要概述所显示的仪表板(顶部导航栏中的选项卡): Scalars显示损失和准确率指标在每个时期如何变化. 您还可以使用它来跟踪训练速度,学习率和其他标量值. Graphs 可帮助您可视化模型 ...

  2. python中tkinter模块窗口操作_Python GUI之tkinter窗口视窗教程大集合(看这篇就够了)...

    本篇博文搬到个人博客:[洪卫の博客](https://sunhwee.com)上面去了,想要获得最佳阅读体验,欢迎前往 [https://sunhwee.com](洪卫の博客), 建议用电脑查看教程文 ...

  3. 一文详解JavaBean 看这篇就够了

    一文详解JavaBean 看这篇就够了 JavaBean的历史渊源 JavaBean的定义(通俗版) JavaBean应用 < jsp:useBean > < jsp:getProp ...

  4. React入门看这篇就够了

    2019独角兽企业重金招聘Python工程师标准>>> 摘要: 很多值得了解的细节. 原文:React入门看这篇就够了 作者:Random Fundebug经授权转载,版权归原作者所 ...

  5. uiautomation遍历windows所有窗口_万字长文!滑动窗口看这篇就够了!

    大家好,我是小浩.今天是小浩算法 "365刷题计划" 滑动窗口系列 - 整合篇.之前给大家讲解过一些滑动窗口的题目,但未作系统整理. 所以我就出了这个整合合集,整合工作中除了保留原 ...

  6. .NET Core实战项目之CMS 第五章 入门篇-Dapper的快速入门看这篇就够了

    写在前面 上篇文章我们讲了如在在实际项目开发中使用Git来进行代码的版本控制,当然介绍的都是比较常用的功能.今天我再带着大家一起熟悉下一个ORM框架Dapper,实例代码的演示编写完成后我会通过Git ...

  7. .NET Core实战项目之CMS 第二章 入门篇-快速入门ASP.NET Core看这篇就够了

    本来这篇只是想简单介绍下ASP.NET Core MVC项目的(毕竟要照顾到很多新手朋友),但是转念一想不如来点猛的(考虑到急性子的朋友),让你通过本文的学习就能快速的入门ASP.NET Core.既 ...

  8. [译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了

    园子里关于ASP.NET Core Web API的教程很多,但大多都是使用EF+Mysql或者EF+MSSQL的文章.甚至关于ASP.NET Core Web API中使用Dapper+Mysql组 ...

  9. ASP.NET Core WebApi使用Swagger生成api说明文档看这篇就够了

    引言 在使用asp.net core 进行api开发完成后,书写api说明文档对于程序员来说想必是件很痛苦的事情吧,但文档又必须写,而且文档的格式如果没有具体要求的话,最终完成的文档则完全取决于开发者 ...

最新文章

  1. 裂痕第一至五季/以法之名Damages迅雷下载
  2. 三、入门实例----基于注解
  3. 求约束条件下极值的拉格朗日乘子法
  4. 【流媒体服务器的搭建】1. 源码编译安装x264
  5. [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(5)(IEnumerable补充)
  6. Keil C51,内存与指针
  7. leetcode109. 有序链表转换二叉搜索树(递归)
  8. LINQ to SQL语句(1)之Where
  9. svn服务器安装与配置
  10. python django mysql结果获取_Django中从mysql数据库中获取数据传到echarts方式
  11. 语音识别概念午后大跌 语音识别概念股一览表
  12. 计算机软件在哪里建文本文档,如何新建文档
  13. 【必修】人工智能原理 学习笔记(二)chapter 2 产生式系统
  14. 关于表单流程设计器 以及 问卷调查生成器的开发准备
  15. 亚马逊仓库部署机器人:每小时挑拣物品为过去三倍
  16. 应用内moniter
  17. WINVNC源码阅读(七)
  18. openssl官网-下载安装过程
  19. Visual SLAM 笔记——李群和李代数详解
  20. 高斯求和问题(C语言程序设计)

热门文章

  1. PAT L2-027. 名人堂与代金券
  2. Android基础入门教程——8.3.18 Canvas API详解(Part 3)Matrix和drawBitmapMash
  3. 数字摄影测量特征点提取之SUSAN算子
  4. [已解决]用wget下载GES DISC数据遇到unable to establish SSL connection的问题
  5. Servlet从本机读取一个图片,并显示在html页面
  6. java的(String)字符串方法
  7. Android Studio TCP客户端实现
  8. 如何用HTML写一个旋转万花筒
  9. 闸门开度仪是怎么控制闸门开度的?
  10. BJDCTF 2nd-WP