文章目录

  • 前言
  • 一、概念
    • 1.1 顺序容器
    • 1.2 容器适配器
    • 1.3 关联容器
  • 二、程序示例
    • 1. vector和Set自定义数据类型的访问
    • 2.vector容器嵌套
    • 3.list容器排序
    • 4.pair对组的使用
  • 总结

前言

STL是C++中的基于数据结构和算法的标准模板库,可以大量节约系统开发时间,增加程序复用性。
STL的六大件包括容器、算法、迭代器、仿函数、适配器和空间配置器,其中几乎所有代码均使用了模板类和模板函数的概念。

一、概念

容器从字面意思理解就是放东西的器件,C++中的容器是指将对象放入存储对象的模板类型里。
容器有以下几种:

1.1 顺序容器

顺序容器也叫序列式容器,是各元素之间存在顺序关系的线性表,其中元素的位置固定,但可用删除或插入的操作进行改变,这种操作称为质变算法。

顺序容器由vector(向量)、list(列表)、deque(队列)组成。

vector是最常见的容器类型,访问其中的数据有很多方法,这里使用迭代器完成,一般使用iterator迭代器,它是指针的泛化,声明的对象可以用*+对象完成查看。与普通数组的不同之处在于vector是可以动态扩展的数据结构,没有长度的限制,其原理是重新开辟新空间来拷贝原来的数组内容,然后删除原有空间。
其缺陷在于对头部进行插入或删除时效率较低。

//头文件
#include<vector>//定义容器
vector<int> v;
//插入数据
v.push_back(1);
v.push_back(3);
v.push_back(5);
//访问数据1
for (vector<int>::iterator i = v.begin(); i != v.end(); i++)
{cout << *i << endl;
}
//[]和at访问
cout << v[0] << endl;
cout << v.at(0) << endl;
//拷贝构造完成赋值
vector<int>v2(v);
v2.resize(3);
v2.insert(v2.begin(),100);
v2.erase(v2.begin());

deque(double-ended queue:双端队列)是一种对两端元素进行添加和删除操作的容器,又称双端数组,应用方式基本和vector一样。
其特点:
1: 采用多个连续的内存存储数据,并且在一个映射结构中保存对这些内存和顺序的跟踪,索引数组是存储每段数组的首地址。
2:和vevtor不同,deque向两端插入或删除元素时效率较高,但中间效率较低。
3:deque在访问元素时比vector慢。
4:deque的迭代器也支持随机访问数组元素。
工作原理:
deque是由一个中控器来维护缓冲区的地址,其中缓冲区存放数据。

 deque<int>d;for (int i = 0; i < 10; i++){d.push_back(i);}PrintDeque(d);deque<int>d1(d.begin(), d.end());PrintDeque(d1);//赋值deque<int>d2;d2 = d1;PrintDeque(d2);deque<int>d3;//尾插d3.push_back(1);//头插d3.push_front(2);PrintDeque(d3);d3.insert(d3.begin(), 3);PrintDeque(d3);deque<int>::iterator i = d3.begin();d3.erase(i);//默认从小到大sort(d3.begin(), d3.end());PrintDeque(d3);d3.clear();PrintDeque(d3);

list叫双向链表,其数据元素是通过链表指针串连成的线性表,由节点表示元素位置,节点由三部分组成,前驱元素指针域、数据域和后继元素指针域。前驱元素指针域保存了前驱元素的首地址;数据域则是本节点的数据;后继元素指针域则保存了后继元素的首地址。迭代器也是双向迭代器。
缺点:
1:由于list元素节点并不要求在一段连续的内存中,故不支持快速随机存取,只能通过“++”或“–”操作将迭代器移动到后继/前驱节点元素处。
2:遍历速度慢,是用指针进行读取的。
3:占用内存大。
优点:
1:可以快速的插入和删除数据。原因是list是通过指针指向来串联的,插入元素的时候只需要让前后的指针指向新的元素节点即可,不需移动元素位置。
2:采用动态分配内存,不会浪费。

 //构造函数list<int>l;l.push_back(1);l.push_back(2);l.push_back(3);
list<int>l2(l.begin(),l.end());PrintList(l2);list<int>l3(l2);PrintList(l3);list<int>l4(3,10);PrintList(l4);//赋值list<int>l5;l5 = l4;list<int>l6;l6.assign(l5.begin(), l5.end());list<int>l7;l7.assign(3, 10);PrintList(l7);//交换l.swap(l7);PrintList(l);PrintList(l7);//存取cout<<l.front()<<endl;cout << l.back() << endl;//list不支持随机访问list<int>::iterator i = l.begin();i++;//支持++,--访问元素i--;//反转l.swap(l7);l.reverse();PrintList(l);

1.2 容器适配器

容器适配器包括stack,queue,priority_queue三种,可以让基本的容器类型采用另一种更适配于当前工作要求的工作方式实现。三种适配器都需满足一定的约束条件,也可以可理解为加了限制条件的容器。

stack称为栈容器,是以deque为底层容器,封闭一些功能而形成一种具有“先进后出”特性,并不允许遍历行为的容器适配器,所以stack没有迭代器。

    #include<stack>stack<int>s;//从栈顶入栈s.push(1);s.push(2);//判断栈顶是否为空,出栈while (!s.empty()){cout << s.top() << endl;s.pop();}cout << s.size()<<endl;

queue又称队列,必须符合先进先出原则,也不允许遍历成员,所以也没有迭代器。

#include<iostream>
#include<string>
#include<queue>
#include<algorithm>
using namespace std;void test()
{queue<int>s;//从队顶入队s.push(1);s.push(2);//判断队头是否为空,出队while (!s.empty()){cout << s.front()<< endl;cout << s.back()<<endl;s.pop();}cout << s.size() << endl;
}int main()
{test();system("pause");
}

priority_queue称为优先队列,自定义数据的优先级, 让优先级高的排在队列前面, 可以优先出队。

#include <queue>priority_queue<int> a;for (int i = 0; i < 10; i++){a.push(i);}while (!a.empty()){cout << a.top() << ' ';a.pop();}cout << endl;

1.3 关联容器

关联容器是一种二叉树的结构,没有严格的顺序关系,元素位置会按照二叉树的排序方式进行,在排序的时候按照升序排列。
主要包含有三种,set(集合),multiset(多重集合),map,multimap。

set和multiset均可以进行快速查找数据,但区别在于set容器不允许有重复值,multiset可以有。
set在内存中是通过链表进行排序的,所以插入时比vector和deque要快,但是比list慢;在访问元素上比vector 慢,比list快,原因是list 是逐个搜索,它搜索的时间是跟容器的大小成正比,而关联容器 查找的复杂度是Log(N) ,比vector少。

void printSet(set<int>&s)
{for (set<int>::iterator i = s.begin(); i != s.end(); i++){cout << *i << " ";}cout << endl;
}
//降序.声明仿函数
class Comparedown
{public:bool operator()(int a, int b)const{return a > b;}
};int main()
{set<int>s;//只能使用insert方法插入数据s.insert(1);s.insert(2);s.insert(3);//遍历容器printSet(s);//拷贝构造set<int>s2(s);printSet(s2);//赋值set<int>s3;s3 = s2;printSet(s3);//插入s.insert(4);s.erase(s.begin());s.erase(2);printSet(s);//互换s.swap(s2);//查找set<int>::iterator i = s.find(3);if (i!= s.end()){cout << *i << endl;}else{cout << "null" << endl;}//统计int n = s.count(3);cout << n << endl;//排序set<int, Comparedown>s5;s5.insert(3);s5.insert(2);for (set<int, Comparedown>::iterator i = s5.begin(); i != s5.end(); i++){cout << *i << " ";}//多重集合multiset<int>ms;ms.insert(1);ms.insert(1);for (multiset<int>::iterator i = ms.begin(); i != ms.end(); i++){cout << *i << " ";}
}

map 提供一种“键-值”关系的一对一的数据存储能力,所有元素都是pair类型。
pair的第一个元素是键值,第二个为value值。
键值即索引值,在容器中不可重复,其内部按链表的方式存储,故也继承了链表的优缺点,在插入时所有元素都会根据键值自动排序。
与set相似,multimap可以实现重复数据的存储。

void printMap(map<int,int>&m)
{for (map<int,int>::iterator i = m.begin(); i != m.end(); i++){cout <<"key=" << (*i).first <<" " <<"value=" << i->second<<endl;}cout << endl;
}class Comparedown
{public:bool operator()(int a, int b)const{return a > b;}
};void test()
{map<int, int>m;//插入数据m.insert(pair<int, int>(1, 2));m.insert(pair<int, int>(3, 4));m.insert(make_pair(2, 6));m.insert(make_pair(5, 34));m.insert(map<int, int>::value_type(7, 8));printMap(m);//拷贝构造map<int, int>map1(m);//赋值map<int, int>map2;map2 = m;//按key进行删除m.erase(1);printMap(m);//按key查找map<int, int>::iterator i = m.find(3);if (i != m.end()){cout << i->first << i->second << endl;}else{cout << "未找到" << endl;}//统计key,但key不重复,所以n值为0或1int n = m.count(3);cout << n << endl;//用仿函数完成从大到小排序map<int, int,Comparedown>map4;map4.insert(make_pair(2, 6));map4.insert(make_pair(6, 6));map4.insert(make_pair(3, 6));for (map<int, int, Comparedown>::iterator i = map4.begin(); i != map4.end(); i++){cout << "key=" << (*i).first << " " << "value=" << i->second << endl;}
}int main()
{test();system("pause");
}

二、程序示例

1. vector和Set自定义数据类型的访问

class Person
{public:Person(string name, int age){this->Name = name;this->Age = age;}string Name;int Age;
};
//存数据
void test()
{//vectorvector<Person> v;Person p1("sun", 4);Person p2("aun", 3);Person p3("cun", 2);Person p4("dun", 1);v.push_back(p1);v.push_back(p2);v.push_back(p3);v.push_back(p4);for (vector<Person>::iterator i = v.begin(); i != v.end(); i++){cout << (*i).Name <<"  " <<(*i).Age<<endl;cout << i->Name << "  " << i->Age << endl;}//setset<Person> s;Person p1("sun", 4);Person p2("aun", 3);Person p3("cun", 2);Person p4("dun", 1);
}//存指针
void test1()
{vector<Person*> v;Person p1("sun", 4);Person p2("aun", 3);Person p3("cun", 2);Person p4("dun", 1);v.push_back(&p1);v.push_back(&p2);v.push_back(&p3);v.push_back(&p4);for (vector<Person*>::iterator i = v.begin(); i != v.end(); i++){cout << (*(*i)).Name <<" " << (*(*i)).Age<< endl;cout << (*i)->Name << " " << (*i)->Age << endl;}
}

2.vector容器嵌套

void test()
{vector<vector<int>>doublev;//创建内层容器vector<int>doublev1;//放数据for (int i = 0; i < 3; i++){doublev1.push_back(i + 1);}//放入外层容器doublev.push_back(doublev1);//遍历数据for (vector<vector<int>>::iterator i = doublev.begin(); i != doublev.end(); i++){for (vector<int>::iterator j = (*i).begin(); j != (*i).end(); j++){cout << *j << endl;cout << &j << endl;//内层嵌套的迭代器指针地址}cout << &i << endl;//外层嵌套的迭代器指针地址}
}

3.list容器排序

class Cat
{public:Cat(string name, int color,int age){this->Name = name;this->Color = color;this->Age = age;}public:string Name;int Color;int Age;
};//指定排序规则
bool Compare(Cat& c1, Cat& c2)
{if (c1.Color == c2.Color){return c1.Age < c2.Age;}else{return c1.Color < c2.Color;}
}void test()
{list<Cat>L;Cat cat1("小100", 76, 3);Cat cat2("小200", 32, 2);Cat cat3("小300", 32, 4);Cat cat4("小400", 32, 3);Cat cat5("小500", 54, 1);//插入L.push_back(cat1);L.push_back(cat2);L.push_back(cat3);L.push_back(cat4);L.push_back(cat5);for (list<Cat>::iterator i = L.begin(); i != L.end(); i++){cout << (*i).Name << " " << (*i).Color << " " << (*i).Age << endl;}L.sort(Compare);for (list<Cat>::iterator i = L.begin(); i != L.end(); i++){cout << (*i).Name << " " << (*i).Color << " " << (*i).Age << endl;}
}int main()
{test();system("pause");
}

4.pair对组的使用

pair是一个模板结构体类型,set集合的insert方法就是pair类模板定义的,pair的参数类型有两种,一个是迭代器,另外一个是bool类。bool返回迭代器是否应用方法成功,pair里的对象可以由pair的两个函数first和second访问。

multiset只返回迭代器类型,故可以重复插入。

//set
pair<iterator, bool> insert(value_type&& _Val)
{const auto _Result = _Emplace(_STD move(_Val));return {iterator(_Result.first, _Get_scary()), _Result.second};
}
//pair定义
struct pair { // store a pair of values
using first_type  = _Ty1;
using second_type = _Ty2;//multiset
iterator insert(value_type&& _Val)
{return iterator(_Emplace(_STD move(_Val)).first, _Get_scary());
}
//
pair<set<int>::iterator, bool> p = s.insert(4);
if (p.second)//first返回迭代器,second返回bool
{cout << "插入成功" << endl;
}

pair既可以将2个数据组合成一组数据,也可以让函数返回2个数据,具体应用如下:

 pair<string, int> p1(string("a"), 3);cout << p1.first << p1.second << endl;pair<string, int> p2 = make_pair(string("a"), 3);cout << p2.first << p2.second << endl;

总结

容器的构造函数和成员函数的调用规则基本是类似的,但每种都会存在一点差别,重点记忆vector, list,map三种的调用方式。

C++STL总结笔记(一)—— 容器和容器适配器相关推荐

  1. C++ STL学习笔记 : 2. unordered map 容器

    本文中,简单总结一下使用unordered map 的心得.unordered_map容器属于STL中关联表的一种,常用的map容器与unordered_map容器在使用中有着很大程度的相同点,在之后 ...

  2. C++ STL学习笔记

    C++ STL学习笔记一 为何要学习STL: 数据结构与算法是编程的核心,STL中包含各种数据结构和优秀的算法,确实值得深入学习,本文中虽然着重使用,但希望有心的朋友能多看看相关数据结构的实现,对于C ...

  3. 【C++ STL学习笔记】C++ STL序列式容器(array,vector,deque,list)

    文章目录 C++ STL容器是什么? 迭代器是什么,C++ STL迭代器(iterator)用法详解 迭代器类别 迭代器的定义方式 C++序列式容器(STL序列式容器)是什么 容器中常见的函数成员 C ...

  4. C++|STL学习笔记-对STL中关联容器map的进一步认识

    关联容器map key + value 的值 关联容器 = 有序容器(红黑树) + 无序容器(散列表) + hash_map 有序容器中: map的键值是不允许重复的 multimap的键值是允许重复 ...

  5. STL vector的几种清空容器(删除)办法

    1.为什么需要主动释放vector内存 来自 <https://blog.csdn.net/hellokandy/article/details/78500067> vector其中一个特 ...

  6. STL 容器简介:C++ 容器:顺序性容器、关联式容器和容器适配器

    STL标准容器类简介 标准容器类 说明 顺序性容器 vector 从后面快速的插入与删除,直接访问任何元素 deque 从前面或后面快速的插入与删除,直接访问任何元素 list 双链表,从任何地方快速 ...

  7. Flutter学习笔记(10)--容器组件、图片组件

    如需转载,请注明出处:Flutter学习笔记(10)--容器组件.图片组件 上一篇Flutter学习笔记(9)--组件Widget我们说到了在Flutter中一个非常重要的理念"一切皆为组件 ...

  8. Java编程笔记16:深入容器

    Java编程笔记16:深入容器 图源:PHP中文网 填充容器 填充容器会有Java编程笔记15:数组 - 魔芋红茶's blog (icexmoon.cn)种提到的填充数组同样的问题. 和数组类似,标 ...

  9. 学习笔记:云原生容器化技术——Docker

    Docker学习笔记 前言 一.Docker概述 1.1 Docker为什么会出现? 1.2 Docker的历史 1.3 Docker为什么这么火爆? 1.4 虚拟机技术与容器化技术的区别 二.Doc ...

最新文章

  1. div渐变遮罩效果:纵向和水平反向渐变遮罩效果,让戛然而止的页面多一丝丝淡淡的过渡效果,温柔中透露着一缕缕优雅...
  2. AI一分钟 | Windows负责人离职;华为2017年收入6036亿元,净利475亿元
  3. python程序员在公司都是做什么的-为什么企业很难招聘到好的python程序员?
  4. sphinx-release 2.1.4
  5. micropython是啥 知乎_micropython入门教程
  6. DCMTK:DcmItem和DcmSequenceOfItem的路径功能测试程序
  7. SharePoint Portal Server 2003 SP2对文档库事件处理程序所带来的影响
  8. 数据中心SDN技术发展应用之MP-BGP
  9. 我刚做的一个TreeView的CheckBox进行选中插入数据库,从数据库中读取数据后让CheckBox勾选的代码!...
  10. 数据结构+算法面试100题~~~摘自CSDN,作者July
  11. Elasticsearch7.15.2 出现 node validation exception 的问题处理
  12. 新浪微博时间格式解析java_仿新浪微博格式化时间
  13. C++实现的Miller-Rabin素性测试程序
  14. 错误:无法与 SFTP 服务器建立 FTP 连接
  15. 《延世大学韩国语教程2》第二十课 办公室(上)
  16. 【待填坑】js构造函数和内置对象的区别
  17. golang1.1-基础环境的配置以及事项
  18. 转接口IC ADV7280/ADV7280-M:CVBS转MIPI芯片 10位、4倍过采样标清电视视频解码器,支持去隔行
  19. 1487: [HNOI2009]无归岛
  20. 第二章 前端开发——JavaScript

热门文章

  1. Javascript面向对象编程:构造函数的继承
  2. Highcharts图表-ajax-获取json数据生成图表
  3. Linux进程管理之ps的使用
  4. scrapy爬虫系列之三--爬取图片保存到本地
  5. Angular 路由守卫
  6. springboot之session、cookie
  7. 『Python基础-12』各种推导式(列表推导式、字典推导式、集合推导式)
  8. 001-Ansible-参考http://www.ansible.com.cn/docs/playbooks_intro.html#about-playbooks
  9. 关于常用meta的总结
  10. Java(Android)线程池