1.C++ STL标准库简介

长久以来,软件界一直希望建立一种可重复利用的东西,以及一种得以制造出”可重复运用的东西”

的方法,从函数(functions),类别(classes),函数库(function libraries),类别库(class libraries)、各种

组件,从模块化设计,到面向对象(object oriented ),为的就是复用性的提升。

复用性必须建立在某种标准之上。但是在许多环境下,就连软件开发最基本的数据结构(data

structures) 和算法(algorithm)都未能有一套标准。大量程序员被迫从事大量重复的工作,竟然是为

了完成前人已经完成而自己手上并未拥有的程序代码,这不仅是人力资源的浪费,也是挫折与痛苦

的来源。

为了建立数据结构和算法的一套标准,并且降低他们之间的耦合关系,以提升各自的独立性、弹

性、交互操作性(相互合作性,interoperability),诞生了STL。

STL(Standard Template Library,标准模板库),是惠普实验室开发的一系列软件的统称。现在主要

出现在 c++中,但是在引入 c++之前该技术已经存在很长时间了。

STL 从广义上分为: 容器(container) 算法(algorithm) 迭代器(iterator)。

容器和算法之间通过迭代器进行无缝连接。STL 几乎所有的代码都采用了模板类或者模板函数,这

相比传统的由函数和类组成的库来说提供了更好的代码重用机会。

STL(Standard Template Library)标准模板库,在我们 c++标准程序库中隶属于 STL 的占到了 80%以

上。

2.STL容器使用时机

. vector deque list set multiset map multimap
典型内存结构 单端数组 双端数组 双向链表 二叉树 二叉树 二叉树 二叉树
可随机存取 对key而言:不是
元素搜寻速度 非常慢 对key而言:快 对key而言:快
元素安插移除 尾端 头尾两端 任何位置 - - - -

vector的使用场景:比如软件历史操作记录的存储,我们经常要查看历史记录,比如上一次的记

录,上上次的记录,但却不会去删除记录,因为记录是事实的描述。

deque的使用场景:比如排队购票系统,对排队者的存储可以采用deque,支持头端的快速移除,

尾端的快速添加。如果采用vector,则头端移除时,会移动大量的数据,速度慢。

vector与deque的比较:

一:vector.at()比deque.at()效率高,比如vector.at(0)是固定的,deque的开始位置 却是不固定的。

二:如果有大量释放操作的话,vector花的时间更少,这跟二者的内部实现有关。

三:deque支持头部的快速插入与快速移除,这是deque的优点。

list的使用场景:比如公交车乘客的存储,随时可能有乘客下车,支持频繁的不确实位置元素的移

除插入。

set的使用场景:比如对手机游戏的个人得分记录的存储,存储要求从高分到低分的顺序排列。

map的使用场景:比如按ID号存储十万个用户,想要快速要通过ID查找对应的用户。二叉树的查找

效率,这时就体现出来了。如果是vector容器,最坏的情况下可能要遍历完整个容器才能找到该用

户。

3.vector容器

vector的数据安排以及操作方式,与array非常相似,两者的唯一差别在于空间的运用的灵活性。

Array是静态空间,一旦配置了就不能改变,要换大一点或者小一点的空间,可以,一切琐碎得由

自己来,首先配置一块新的空间,然后将旧空间的数据搬往新空间,再释放原来的空间。

Vector是动态空间,随着元素的加入,它的内部机制会自动扩充空间以容纳新元素。因此vector的

运用对于内存的合理利用与运用的灵活性有很大的帮助,我们再也不必害怕空间不足而一开始就要

求一个大块头的array了。

Vector的实现技术,关键在于其对大小的控制以及重新配置时的数据移动效率,一旦vector旧空间

满了,如果客户每新增一个元素,vector内部只是扩充一个元素的空间,实为不智,因为所谓的扩

充空间(不论多大),一如刚所说,是”配置新空间-数据移动-释放旧空间”的大工程,时间成本很高,

应该加入某种未雨绸缪的考虑,稍后我们便可以看到vector的空间配置策略。

基本使用:

#include "stdafx.h"
#include <iostream>#include <vector>//动态数组
using namespace std;int main()
{vector<int>  v1;//构造一个空的vectorcout << "容量为:"<<v1.capacity() << "     元素个数: " << v1.size() << endl;vector<int>  v2(5);//构造一个空间大小为5,并且元素为5个(有默认值)的vectorcout << "容量为:" << v2.capacity() << "     元素个数: " << v2.size() <<"       v2[0]:"<<v2[0]<< endl;vector<int>  v3(5,111);//构造一个空间大小为5,并且元素为5个(每个元素初始值为111)的vectorcout << "容量为:" << v3.capacity() << "     元素个数: " << v3.size() << "       v3[0]:" << v3[0] << endl;vector<int>  v4(v3);//拷贝构造vectorcout << "容量为:" << v4.capacity() << "     元素个数: " << v4.size() << "    v4[0]:" << v4[0] << endl;//像数组一样的访问vectorv2[0] = 1;//vector重载了[]运算符v2[1] = 2;v2[2] = 3;v2.at(3) = 4;v2.at(4) = 5;for (size_t i = 0; i < v2.size(); i++){//cout << v2[i] << "    ";//cout << v2.at(i)<< "  ";cout << &v2[i] << " ";//输出地址,说明存储空间是连续的}cout << endl;return 0;
}

迭代器使用:

#include<iostream>
#include<vector>//动态数组
using namespace std;template<class T>
void   Print(T  begin, T  end)
{//此处编写代码for (T p = begin; p != end; ++p){cout << *p << "      ";}cout << endl;
}int main()
{vector<int>  v(5);//构造一个空间大小为5,并且元素为5个(有默认值)的vector//像数组一样的访问vectorv[0] = 1;//vector重载了[]运算符v[1] = 2;v[2] = 3;v.at(3) = 4;v.at(4) = 5;for (size_t i = 0; i < v.size(); i++){cout << v[i] << "   ";}cout << endl;{//验证vector的迭代器是随机访问迭代器(支持++  、-- 、 +n、  +=n 、-=n 、 -n 、 *、[]   )//random_access_iteratorcout << typeid(vector<int>::iterator::iterator_category).name() << endl;vector<int>::iterator  it = v.begin();//begin返回v的第一个元素的迭代器cout << "v开头的迭代器指向的元素值:" << *it << endl;++it;//it的值改变cout << "v第二个的元素值:" << *it << endl;cout << "v第四个的元素值:" << *(it + 2) << endl;//此刻这里的it还是指向第二个,没变it -= 1;//it的值改变cout << "v第一个的元素值:" << *it << endl;cout << "v第五个的元素值:" << it[4] << endl;//这里的it没变
}//可以改变指向元素的值vector<int>::iterator  it = v.begin();*it = 111;//使用迭代器遍历元素for (vector<int>::iterator  it = v.begin() ;   it!=v.end(); it++){cout << *it << "   ";}cout << endl;//常迭代器  指向的元素值不可改变,  类似  const int  *p; vector<int>::const_iterator   it2 = v.cbegin();//*it2 = 111;//反向迭代器for (vector<int>::reverse_iterator  it3 = v.rbegin(); it3 != v.rend(); it3++){cout << *it3 << "    ";}cout << endl;//测试我们自己实现的Print算法,迭代器架起了 算法与容器之间的桥梁Print<vector<int>::iterator>(v.begin(), v.end());Print(v.begin(), v.end());Print<vector<int>::reverse_iterator>(v.rbegin(), v.rend());return 0;
}

添加、删除、插入元素:

#include<iostream>
#include<vector>
using namespace  std;int main()
{vector<int >   v;//定义一个空的动态数组cout << "容量:" << v.capacity() << "     元素个数:" << v.size() << endl;//往尾部插入元素   //    1v.push_back(1);cout << "容量:" << v.capacity() << "       元素个数:" << v.size() << endl;v.push_back(2);     //      1  2 cout << "容量:" << v.capacity() << "        元素个数:" << v.size() << endl;//向某一个迭代器指向的位置插入v.insert(v.begin(), 3);//    3  1   2cout << "容量:" << v.capacity() << "        元素个数:" << v.size() << endl;//向某一个迭代器指向的位置插入2个值为4的元素v.insert(v.end()-1 ,  2, 4);//    3  1      4  4  2cout << "容量:" << v.capacity() << "      元素个数:" << v.size() << endl;//使用迭代器遍历for (vector<int >::const_iterator   it =  v.cbegin();   it!=  v.cend(); it++){cout << *it << "      ";}cout << endl;//访问第一个元素cout <<"front        " <<v.front() << endl;//访问最后一个元素cout << "back       " << v.back() << endl;//访问某一个下标的元素cout << "at           " << v.at(3) << endl;//删除最后一个元素v.pop_back();cout << "容量:" << v.capacity() << "        元素个数:" << v.size() << endl;//删除开头的元素v.erase(v.begin());cout << "容量:" << v.capacity() << "     元素个数:" << v.size() << endl;//删除结尾的元素, end()指向最后一个元素的下一个v.erase(v.end()-1);cout << "容量:" << v.capacity() << "      元素个数:" << v.size() << endl;//使用迭代器遍历for (vector<int >::const_iterator it = v.cbegin(); it != v.cend(); it++){cout << *it << "       ";}cout << endl;//删除所有元素,不会清除容量v.clear();cout << "容量:" << v.capacity() << "      元素个数:" << v.size() << endl;/*当size和capacity相等时继续添加数据,否则vector会扩容,每次扩容都是增加当前空间的1/2(第一次除外);*/{vector<int>  v;cout << "------------------------capacity容量随元素个数size增加的规律----------------------------" << endl;for (int i = 0; i < 50; i++){v.push_back(i);cout << "v的容量:" << v.capacity() << "  元素个数:" << v.size() << endl;}}return 0;
}

vector常用赋值操作:

assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem);//将n个elem拷贝赋值给本身。
vector& operator=(const vector  &vec);//重载等号操作符
swap(vec);// 将vec与本身的元素互换。

vector大小操作:

size();//返回容器中元素的个数
empty();//判断容器是否为空
resize(int num);//重新指定容器的长度为num,若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
resize(int num, elem);//重新指定容器的长度为num,若容器变长,则以elem值填充新位置。如果容器变短,则末尾超出容器长>度的元素被删除。
capacity();//容器的容量
reserve(int len);//容器预留len个元素长度,预留位置不初始化,元素不可访问。

vector数据存取操作:

at(int idx); //返回索引idx所指的数据,如果idx越界,抛出out_of_range异常。
operator[];//返回索引idx所指的数据,越界时,运行直接报错
front();//返回容器中第一个数据元素
back();//返回容器中最后一个数据元素

vector插入和删除操作:

insert(const_iterator pos, int count,ele);//迭代器指向位置pos插入count个元素ele.
push_back(ele); //尾部插入元素ele
pop_back();//删除最后一个元素
erase(const_iterator start, const_iterator end);//删除迭代器从start到end之间的元素
erase(const_iterator pos);//删除迭代器指向的元素
clear();//删除容器中所有元素

vector排序:

sort(nums.begin(),nums.end());

定义二维vector:

vector<vector<int>> v;

创建m*n的二维vector:

vector<vector <int> >nums(m ,vector<int>(n)); //m*n的二维vector

初始化二维数组:

vector<vector<int>> nums(m ,vector<int>(n,0)); //m*n的二维vector,所有元素为0

二维数组遍历:

int m = nums.size(),n = nums[0].size();
for(int i = 0; i < m; i++){for(int j = 0; j < n; j++){cout<<nums[i][j]<<endl;}
}

4.deque容器

Vector容器是单向开口的连续内存空间,deque则是一种双向开口的连续线性空间。

所谓的双向开口,意思是可以在头尾两端分别做元素的插入和删除操作,当然,vector容器也可以

在头尾两端插入元素,但是在其头部操作效率奇差,无法被接受。

deque容器实现原理:

Deque容器是连续的空间,至少逻辑上看来如此,连续现行空间总是令我们联想到array和

vector,array无法成长,vector虽可成长,却只能向尾端成长,而且其成长其实是一个假象,事实上

(1) 申请更大空间 (2)原数据复制新空间 (3)释放原空间 三步骤,如果不是vector每次配置新的空间

时都留有余裕,其成长假象所带来的代价是非常昂贵的。

Deque是由一段一段的定量的连续空间构成。一旦有必要在deque前端或者尾端增加新的空间,便

配置一段连续定量的空间,串接在deque的头端或者尾端。Deque最大的工作就是维护这些分段连

续的内存空间的整体性的假象,并提供随机存取的接口,避开了重新配置空间,复制,释放的轮

回,代价就是复杂的迭代器架构。

既然deque是分段连续内存空间,那么就必须有中央控制,维持整体连续的假象,数据结构的设计

及迭代器的前进后退操作颇为繁琐。Deque代码的实现远比vector或list都多得多。

Deque采取一块所谓的map(注意,不是STL的map容器)作为主控,这里所谓的map是一小块连续

的内存空间,其中每一个元素(此处成为一个结点)都是一个指针,指向另一段连续性内存空间,称

作缓冲区。缓冲区才是deque的存储空间的主体。

基本使用 :

#include<iostream>#include<deque>
using namespace  std;int main()
{//空的双端队列deque<int> d;cout << "元素个数" << d.size() << endl;deque<int> d2(5);//指定元素个数,默认值为类型默认值cout << "元素个数" << d2.size() <<"   "<<d2[0]<< endl;deque<int> d3(5,111);//指定元素个数,每一个指定元素值111cout << "元素个数" << d3.size() << "   " << d3[4] << endl;deque<int>  d4(d3);//拷贝构造cout << "元素个数" << d4.size() << "   " << d4[3] << endl;//像数组一样的访问元素(内存空间并不是连续的)d2[0] = 1;d2[1] = 2;d2[2] = 3;d2.at(3) = 4;for (size_t i = 0; i < d2.size(); i++){cout << d2[i] << "       ";}cout << endl;//验证deque的内存空间不是连续的{deque<int>  d;for (size_t i = 0; i < 20; i++){d.push_back(i);cout << "元素" << d[i] << " " << &d[i] << '\t';if ((i + 1) % 4 == 0)cout << endl;} cout << endl; }return 0;
}

 迭代器使用:

#include<iostream>#include<deque>
using namespace  std;template<class T>
void   Print(T  begin, T  end)
{for (T p = begin; p != end; ++p){cout << *p << "      ";}cout << endl;
}int main()
{deque<int> d2(5);//指定元素个数,默认值为类型默认值cout << "元素个数" << d2.size() << "   " << d2[0] << endl;//像数组一样的访问元素(内存空间并不是连续的)d2[0] = 1;d2[1] = 2;d2[2] = 3;d2.at(3) = 4;d2.at(4) = 5;for (size_t i = 0; i < d2.size(); i++){cout << d2[i] << "        ";}cout << endl;//deque<int>::iterator是随机访问迭代器cout << typeid( deque<int>::iterator::iterator_category ).name() << endl;//支持++ 、--、+=n、 -=n、[]、* 、+n、-ndeque<int>::iterator  it = d2.begin();//获取指向容器的第一个元素的迭代器cout << "begin返回的迭代器指向的元素:"<<*it << endl;*it = 111;//deque<int>::iterator可以改变迭代器指向的元素值it++;//下一个元素,it自身改变cout <<"++后:"<< *it << endl;it += 2;//往后移2个位置,it自身改变,指向第4个元素cout << "+=2后:" << *it << endl;cout << "-3后:" << *(it-3) << endl; //  it-3代表it位置的前3个位置,it自身不变cout << "[1]后:" << it[1] << endl; //指向最后一个it = d2.begin();//置为开头cout << "[i]后:" << it[1] << endl; //指向第二个//const_iterator只读的迭代器deque<int>::const_iterator   it2 = d2.cbegin();//*it2 = 11111; //无法改变元素的值,只能读取,类似于 const int  *//使用迭代器正向遍历for (deque<int>::iterator it = d2.begin(); it !=  d2.end(); ++it){cout << *it << "     ";}cout << endl;//使用反向迭代器反向向遍历for (deque<int>::reverse_iterator it = d2.rbegin(); it != d2.rend(); ++it){cout << *it << "     ";}cout << endl;//测试自己写的算法(无需知道deque容器的内存结构,具有通用性)Print<deque<int>::iterator>(d2.begin(), d2.end());Print(d2.rbegin(), d2.rend());//自动推导 return 0;
}

添加、删除、插入元素:

#include<iostream>#include<deque>
using namespace  std;int main()
{deque<int>  d;d.push_back(1);//从尾部插入元素d.push_front(2);//从头部插入元素(vector没有此方法)d.insert(d.begin(), 3);//在迭代器位置插入d.insert(d.end(), 2, 4);//在迭代器位置插入2个元素值为4for ( int  i = 0; i < d.size(); i++){cout <<d[i]<< "      ";}cout << endl;//访问元素//d.at(0) = 111;//d[4] = 555;cout << d.front() << endl;//返回第一个元素cout << d.back() << endl;//返回第一个元素//删除元素d.pop_back();//从尾部删除d.pop_front();//从头部删除(vector不提供)d.erase(d.begin());//删除某个迭代器指向的元素for (int i = 0; i < d.size(); i++){cout << d[i] << "       ";}cout << endl;d.clear();//全部清空cout << "元素个数:"<<d.size() << endl;return 0;
}

deque赋值操作:

assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem);//将n个elem拷贝赋值给本身。
deque& operator=(const deque &deq); //重载等号操作符
swap(deq);// 将deq与本身的元素互换

deque大小操作:

deque.size();//返回容器中元素的个数
deque.empty();//判断容器是否为空
deque.resize(num);//重新指定容器的长度为num,若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
deque.resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置,如果容器变短,则末尾超出容器长度的元素被删除。

deque双端插入和删除操作:

push_back(elem);//在容器尾部添加一个数据
push_front(elem);//在容器头部插入一个数据
pop_back();//删除容器最后一个数据
pop_front();//删除容器第一个数据

deque数据存取:

at(idx);//返回索引idx所指的数据,如果idx越界,抛出out_of_range。
operator[];//返回索引idx所指的数据,如果idx越界,不抛出异常,直接出错。
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位置的数据,返回下一个数据的位置。

5.list容器

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针

链接次序实现的。

链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包

括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。

相较于vector的连续线性空间,list就显得负责许多,它的好处是每次插入或者删除一个元素,就是

配置或者释放一个元素的空间。因此,list对于空间的运用有绝对的精准,一点也不浪费。而且,

对于任何位置的元素插入或元素的移除,list永远是常数时间。

List和vector是两个最常被使用的容器。

List容器是一个双向链表。

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

基本使用:

#include<iostream>#include<list>
using namespace std;int main()
{list<int> l;//空的双向链表cout << "元素个数:" << l.size() << endl;list<int> l2(5);//初始化5个元素,默认值为类型的默认值cout << "元素个数:" << l2.size() <<"  "<<  * (l2.begin() )<< endl;list<int> l3(5,111);//初始化5个元素,每个元素初始值为111cout << "元素个数:" << l3.size() << "  " << *(l3.begin()) << endl;list<int> l4( l3 );//拷贝构造cout << "元素个数:" << l4.size() << "  " << *(l4.begin()) << endl;//不支持[]运算符,因为效率低//cout << l4[0] << endl;//验证了list容器的内存空间是不连续的for (list<int>::iterator   it = l3.begin(); it !=l3.end(); it++){cout << &(*it) << "   ";}cout << endl;return 0;
}

迭代器使用:

#include<iostream>#include<list>
using namespace std;template<class T>
void   Print(T  begin, T  end)
{//此处编写代码for (T p = begin; p != end; ++p){cout << *p << "      ";}cout << endl;
}int main()
{ list<int> l3(5, 111);//初始化5个元素,每个元素初始值为111cout << "元素个数:" << l3.size() << "  " << *(l3.begin()) << endl;//验证list容器的迭代器类型(5种之一)//双向迭代器bidirectional_iterator_tagcout << typeid(list<int>::iterator::iterator_category).name() << endl;//双向迭代器比随机访问迭代器弱一些,支持  ++  --   !=  ==  =  *   不支持[]  +n -n  +=n  -=nlist<int>::iterator  it = l3.begin(); //指向容器l3的第一个元素cout << *it << endl;*(++it) =  222;*(++it) = 333;*(++it) = 444;*(++it) = 555;++it;//指向最后一个元素的下一个cout <<"迭代器指向末尾的下一个"<< (it == l3.end() )<< endl;--it;//指向最后一个元素cout << *it << endl;//it += 3;//不支持//it + 3;//不支持//it[0];//不支持//const_iterator常迭代器,类似于 const  int  *list<int>::const_iterator  it2 = l3.cbegin();//*it2 = 1;//不能修改常迭代器指向的内容//正向遍历for (list<int>::iterator it = l3.begin(); it != l3.end(); it++){cout <<  *it << "   ";}cout << endl;//反向遍历for (list<int>::reverse_iterator it = l3.rbegin(); it != l3.rend(); it++){cout << *it << "   ";}cout << endl;//测试自己的算法(迭代器带来的好处,算法无需关系容器的具体内存结构,就可以遍历)Print<list<int>::iterator>(l3.begin(), l3.end());Print(l3.crbegin(), l3.crend());//自己推到迭代器类型return 0;
}

增加、删除、插入元素:

#include<iostream>#include<list>
using namespace std;int main()
{list<int>  l;//头部插入一个节点(list容器肯定知道头部的位置)l.push_front(111);//尾部插入一个节点(list容器肯定知道尾部的位置)l.push_back(444);l.push_back(555);//在某个迭代器的位置之前插入l.insert(l.begin(), 222);//在某个迭代器的位置之前插入n个相同值元素l.insert(l.begin(), 3,333);//访问链表第一个元素l.front() = 1;cout <<"第一个元素:"<< l.front() << endl; //访问链表最后一个元素cout << "最后一个元素:" << l.back() << endl;for (list<int>::iterator it = l.begin();  it!= l.end(); it++){cout << *it << "      ";}cout << endl;//删除链表头的元素l.pop_front();//删除链表尾的元素l.pop_back();//删除某个迭代器指向的元素l.erase(l.begin());//删除一段迭代器区间l.erase(l.begin(),l.end());//清空链表l.clear();for (list<int>::iterator it = l.begin(); it != l.end(); it++){cout << *it << "      ";}cout << endl;return 0;
}

list数据元素插入和删除操作

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值匹配的元素。

list大小操作

size();//返回容器中元素的个数
empty();//判断容器是否为空
resize(num);//重新指定容器的长度为num,
若容器变长,则以默认值填充新位置。
如果容器变短,则末尾超出容器长度的元素被删除。
resize(num, elem);//重新指定容器的长度为num,
若容器变长,则以elem值填充新位置。
如果容器变短,则末尾超出容器长度的元素被删除。

list赋值操作

assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem);//将n个elem拷贝赋值给本身。
list& operator=(const list &lst);//重载等号操作符
swap(lst);//将lst与本身的元素互换。

list数据的存取

front();//返回第一个元素。
back();//返回最后一个元素。

list反转排序

reverse();//反转链表,比如lst包含1,3,5元素,运行此方法后,lst就包含5,3,1元素。
sort(); //list排序

6.set/multiset容器

set(集合)是一种每个元素值都是唯一的有序的关联容器。

multiset(多重集合)是一种元素值 可复的、有序的 关联容器。

set/multiset容器内部结构采用红黑树(Red-Black tree)的平衡二叉树,它可以在O(logn)时间内

高效的做查找,插入和删除。

基本使用:

#include<set>
#include<vector>
#include<iostream>using namespace  std;int main()
{//set 的特点, 值必须唯一, 有序set<int> s;//构造空的集合,默认less 升序cout << "元素个数" << s.size() << endl;set<int>  s2 = {3,2,5,1,4 ,3};//初始化列表//set<int, greater<int>>  s2 = {3,2,5,1,4 ,3};//初始化列表,降序cout << "元素个数" << s2.size() << endl;set<int>  s3(s2.begin(),s2.end()); //拷贝迭代器范围内的元素cout << "元素个数" << s3.size() << endl;//插入元素 ,成功后返回值的成员second为1,失败为0//cout << typeid(s2.insert(9)).name() << endl; cout<< s2.insert(9).second <<endl;//重复插入元素cout << s2.insert(9).second << endl;vector<int> v = {6,7,8,9};s2.insert(v.begin(), v.end());//插入其它容器中元素的值for (set<int>::iterator   it = s2.begin(); it!=s2.end(); it++){cout << *it << "   ";}cout << endl;//删除值为6的元素s2.erase(6); //删除迭代器指向的元素s2.erase(s2.begin());for (set<int>::iterator it = s2.begin(); it != s2.end(); it++){cout << *it << "   ";}cout << endl;//删除迭代器区间set<int>::iterator it = s2.begin();it++;    it++; it++;s2.erase(s2.begin(), it);//s2.clear();//清空集合元素for (set<int>::iterator it = s2.begin(); it != s2.end(); it++){cout << *it << "   ";}cout << endl;//查找集合中的元素 ,找到返回指向该元素的迭代器,否则返回end()set<int>::iterator it2 = s2.find(99);if (it2 != s2.end()){cout << "找到:" <<*it2<< endl;}else{cout << "未找到!" << endl;}return 0;
}

迭代器使用

STL为set容器提供了相应的迭代器类set<T>::iterator,它是一个双向迭代器(Bidirectional

iterator),以供我们方便的访问容器内部的元素。

#include<set> #include<iostream>
using namespace  std;template<class T>
void   Print(T  begin, T  end)
{for (T p = begin; p != end; ++p){cout << *p << "      ";}cout << endl;
}int main()
{//set 的特点, 值必须唯一, 有序 set<int>  s2 = { 3,2,5,1,4,3 };//初始化列表//输出set迭代器的类别: bidirectional_iterator_tag 双向迭代器cout << typeid(set<int>::iterator::iterator_category).name() << endl;//双向迭代器,支持++ --   *   !=  ==  =  不支持  []  +=n  -=n  +n  -nset<int>::iterator it = s2.begin();//获取第一个元素cout <<"第一个元素"<< *it << endl;// *it = 111;  //不可更改,说明set中元素值不可改变//符合逻辑,因为set中每个元素都已经根据值排列好了大小,此刻你若更改值,顺序无法保证++it;cout << "第二个元素" << *it << endl;--it;cout <<"是否指向开头"<<  (it  ==  s2.begin())<< endl;//常迭代器,不可更改指向的元素的内容set<int>::const_iterator it2 = s2.cbegin();//获取第一个元素// *it2 = 111;  //不可更改set元素中的值//验证下, set<int>::iterator 与 set<int>::const_iterator 是一样的cout << typeid(set<int>::iterator ).name() << endl;cout << typeid(set<int>::const_iterator).name() << endl;//正向遍历for (set<int>::iterator it = s2.begin(); it != s2.end(); it++){cout << *it << "   ";}cout << endl;//反向遍历for (set<int>::reverse_iterator it = s2.rbegin(); it != s2.rend(); it++){cout << *it << "   ";}cout << endl;//测试自定义的Print算法(迭代器,算法无需关心容器的内存结构)Print<set<int>::iterator>(s2.begin(), s2.end());return 0;
}

set赋值操作

set& operator=(const set &st);//重载等号操作符
swap(st);//交换两个集合容器

set大小操作

size();//返回容器中元素的数目
empty();//判断容器是否为空

set插入和删除操作

insert(elem);//在容器中插入元素。
clear();//清除所有元素
erase(pos);//删除pos迭代器所指的元素,返回下一个元素的迭代器。
erase(beg, end);//删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
erase(elem);//删除容器中值为elem的元素。

set查找操作

find(key);//查找键key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();
count(key);//查找键key的元素个数
lower_bound(keyElem);//返回第一个key>=keyElem元素的迭代器。
upper_bound(keyElem);//返回第一个key>keyElem元素的迭代器。
equal_range(keyElem);//返回容器中key与keyElem相等的上下限的两个迭代器。

7.map/multimap容器

map(映射)是一种存储键值(key-value)对, key是唯一的、有序的 关联容器。

multimap(多重映射)是一种存储键值(key-vauekey是 允许重复的、有序的 关联容器。

map内部结构采用红黑树(Red-Black tree)平衡二叉树,它可以在O(log n)时间内高效的做查

找,插入和删除。

Map和list拥有相同的某些性质,当对它的容器元素进行新增操作或者删除操作时,操作之前的所

有迭代器,在操作完成之后依然有效,当然被删除的那个元素的迭代器必然是个例外。

Multimap和map的操作类似,唯一区别multimap键值可重复。

 基本使用 

#include<map>#include<iostream>
using namespace  std;int main()
{//map映射 ,  每个元素都是 key-value 键值对,  key不能重复,value可以,有序的map<int, string>  m;//构造空的mapcout <<"元素个数:"<< m.size() << endl;//初始化列表构造mapmap<int, string>  m2 = { {3,"CCC"} ,  {1,"AAA"} ,  {2,"BBB"} };cout << "元素个数:" << m2.size() << endl;//拷贝构造map<int, string>  m3(m2);cout << "元素个数:" << m3.size() << endl;//验证map容器中的元素类型   pair<int, string>cout << typeid(map<int, string>::value_type).name() << endl;//一对值  pair 类模板pair<int, float>  p1;p1.first = 1;p1.second = 2.34f;pair<int, float>  p2(2, 3.45f); //有参构造cout << "first: " << p2.first << "     second:" << p2.second<< endl;//使用make_pair函数构造pairpair<short, char>  p3 = make_pair<short, char>(3, 'A');//pair<short, char>  p3 = make_pair(3, 'A');//自动推导cout << "first: " << p3.first << "     second:" << p3.second << endl;map<int, string>  m4 = {   pair<int, string>( 3,"CCC" )   ,  make_pair( 2,"BBB"),  make_pair(1,"AAA"), };cout << "元素个数:" << m4.size() << endl;return 0;
}

插入、删除元素

#include<vector>
#include<map>#include<iostream>
using namespace  std;int main()
{//map映射 关联容器 ,  每个元素都是 key-value 键值对  pair, //key不能重复,value可以, 有序的map<int, string>  m;//构造空的map //插入pairpair<int, string>  p1(2, "BBB");m.insert(p1);m.insert(pair<int, string>(1, "AAA"));//可以通过insert返回值的 成员.second查看是否插入成功,true成功,false是失败m.insert( make_pair<int, string>(2, "bbb")); //插入重复的key, 插入失败m.insert(make_pair(3, "CCC")); // 插入其它容器中迭代器范围中的元素vector<pair<int, string>>  v = { {3,"ccc"}, {5, "EEE"},{ 4,"DDD" },{6, "FFF"} };m.insert(v.begin(), v.end());//[key]= value m[7] = "GGG"; //对于不存在的key, 插入,相当于 (7,"GGG") m[8];  //对于不存在的key,插入,相当于 ( 8,"")m[2] = "bbb";// 已经存在的key,相当于是修改元素的valuefor (map<int, string>::iterator  it = m.begin(); it!= m.end(); ++it){cout << it->first << "->" << it->second.c_str() << "   ";}cout << endl;//查找key为3的元素,成功返回迭代器,失败返回end(){map<int, string>::iterator  it = m.find(33);if (it != m.end()){cout << "找到:" << it->first << "->" << it->second.c_str() << endl;}else{cout << "未找到!" << endl;}}//[key] 如果key存在,直接返回value//陷阱 ,如果key不存在,他会自动插入key,value为默认值再返回cout << "[key] "<< m[33].c_str() << endl;for (map<int, string>::iterator it = m.begin(); it != m.end(); ++it){cout << it->first << "->" << it->second.c_str() << "   ";}cout << endl;//删除key为3的元素m.erase(3); //删除某个迭代器指向的元素m.erase(m.begin());//删除迭代器区间[)的元素map<int, string>::iterator it = m.begin();++it; ++it; ++it; //往后移动m.erase(m.begin(), it); //删除所有元素m.clear();for (map<int, string>::iterator it = m.begin(); it != m.end(); ++it){cout << it->first << "->" << it->second.c_str() << "   ";}cout << endl;return 0;
}

迭代器使用

STL为map容器提供了相应的迭代器类map<T1,T2>::iterator,它是一个双向迭代器

(Bidirectional iterator)以供我们方便的访问容器内部的元素。

#include<map>#include<iostream>
using namespace  std;template<class T>
void   Print(T  begin, T  end)
{for (T p = begin; p != end; ++p){cout << *p << "      ";}cout << endl;
}//为   map<int, string>元素类型提供 <<运算符重载
ostream  &  operator<<(ostream  &  os, map<int, string>::value_type   &p)
{cout << p.first << "->" << p.second.c_str() ;return  os;
}int main()
{//map映射 关联容器 ,  每个元素都是 key-value 键值对  pair, //key不能重复,value可以, 有序的map<int, string>  m;//构造空的map  m.insert(make_pair(3, "CCC"));m.insert(make_pair(1, "AAA"));    m.insert(make_pair(2, "BBB")); //map<int, string>::iterator是双向迭代器 bidirectional_iterator_tagcout << typeid(map<int, string>::iterator::iterator_category).name() << endl;//双向迭代器,支持  ++  --  *   =    !=   == ,  不支持   [] 、+=n, -=n  +n  -nmap<int, string>::iterator  it = m.begin();// it->first = 111; //map的key值不允许修改, map是按照key排好序的,如果你更改key值,会打乱顺序it->second = "aaa"; //map的value允许修改++it;cout << it->first << "->" << it->second.c_str() <<endl;--it;cout << "回到开头"<<(it == m.begin()) << endl;//const_iterator 指向的元素内容不可修改map<int, string>::const_iterator  it2 = m.begin();// it2->first = 111; //均不可修改// it2->second = "aaa";//均不可修改//查看两种iterator的真实类型cout << typeid(map<int, string>::iterator).name() << endl;cout << typeid(map<int, string>::const_iterator).name() << endl;//正向遍历for (map<int, string>::iterator it = m.begin(); it != m.end(); ++it){cout << it->first << "->" << it->second.c_str() << "   ";}cout << endl;//反向遍历for (map<int, string>::reverse_iterator it = m.rbegin(); it != m.rend(); ++it){cout << it->first << "->" << it->second.c_str() << "   ";}cout << endl;//使用Print ,无需知道map的内部结构,通过迭代器就可以遍历map的所有元素Print<map<int, string>::iterator>(m.begin(), m.end());return 0;
}

map赋值操作

map& operator=(const map &mp);//重载等号操作符
swap(mp);//交换两个集合容器

map大小操作

size();//返回容器中元素的数目
empty();//判断容器是否为空

map插入数据元素操作

map.insert(...); //往容器插入元素,返回pair<iterator,bool>
map<int, string> mapStu;
// 第一种 通过pair的方式插入对象
mapStu.insert(pair<int, string>(3, "小张"));
// 第二种 通过pair的方式插入对象
mapStu.inset(make_pair(-1, "校长"));
// 第三种 通过value_type的方式插入对象
mapStu.insert(map<int, string>::value_type(1, "小李"));
// 第四种 通过数组的方式插入值
mapStu[3] = "小刘";
mapStu[5] = "小王";

map删除操作

clear();//删除所有元素
erase(pos);//删除pos迭代器所指的元素,返回下一个元素的迭代器。
erase(beg,end);//删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
erase(keyElem);//删除容器中key为keyElem的对组。

map查找操作

find(key);//查找键key是否存在,若存在,返回该键的元素的迭代器;/若不存在,返回map.end();
count(keyElem);//返回容器中key为keyElem的对组个数。对map来说,要么是0,要么是1。对multimap来说,值可能大于1。
lower_bound(keyElem);//返回第一个key>=keyElem元素的迭代器。
upper_bound(keyElem);//返回第一个key>keyElem元素的迭代器。
equal_range(keyElem);//返回容器中key与keyElem相等的上下限的两个迭代器。

C++ - STL标准库相关推荐

  1. C++拾取——使用stl标准库实现排序算法及评测

    今天看了一篇文章,讲各种语言的优势和劣势.其中一个观点:haskell非常适合写算法,因为使用者不用去关心具体的计算机实现,而只要关注于操作语义.这让它在专心研究算法的人中非常受欢迎.所以很多时候,语 ...

  2. STL标准库-容器-set与map

    STL标准库-容器-set与multiset C++的set https://www.cnblogs.com/LearningTheLoad/p/7456024.html STL标准库-容器-map和 ...

  3. C++的STL标准库学习(queue)队列(第四篇)

    queue容器基本概念 Queue是一种先进先出(First In First Out,FIFO)的数据结构,它有两个出口,queue容器允许从一端新增元素,从另一端移除元素.  也就是说输入的数据要 ...

  4. C++的STL标准库学习(stack)栈

    stack是一种先进后出(First In Last Out,FILO)的数据结构,它只有一个出口,形式如图所示.stack容器允许新增元素,移除元素,取得栈顶元素,但是除了最顶端外,没有任何其他方法 ...

  5. C++STL标准库学习笔记(一)sort

    目录 前言: 正文 一.排序(sort) 用法1:对基本类型的数组(int,double,char...)从小到大排序 用法2:对元素类型为T的基本类型数组从大到小排序: 用法3:用自定义的排序规则, ...

  6. STL标准库及泛型编程

    1-认识headers.版本.重要资源 C++ Standard Library Standard Template Library 标准库 > STL 标准库以header files形式呈现 ...

  7. C++STL标准库学习总结/索引/学习建议

    前言: 如果刚刚开始学习STL标准库,不知道从哪里入手学习的话,建议去中国大学mooc平台,先学习北京大学郭炜老师的<程序设计与算法(一)C语言程序设计>(https://www.icou ...

  8. 侯捷C++课程笔记03: STL标准库与泛型编程

    本笔记根据侯捷老师的课程整理而来:STL标准库与泛型编程 pdf版本笔记的下载地址: 笔记03_STL标准库与泛型编程,排版更美观一点(访问密码:3834) 侯捷C++课程笔记03: STL标准库与泛 ...

  9. 【侯捷】C++STL标准库与泛型编程(第二讲)

    第二讲 应具备的基础 C++基本语法 模板(Template)基础 令你事半功倍 数据结构(Data Structures)和算法(Algorithms)概念 令你如鱼得水 书籍: <Algor ...

最新文章

  1. 五个计算机软件,近五个交易日计算机软件概念股市复盘(4月19日)
  2. 陇东学院c语言程序设计,C语言程序设计
  3. java生成j动态页面_zk动态产生多个页面的例子代码
  4. 多功能照片图片处理器小程序源码_支持流量主
  5. ThinkPHP文件目录说明
  6. 综合后端各种类型文件
  7. SQL的3种连接查询
  8. python毕业设计总结范文大全_关于毕业设计总结范文
  9. GD32 程序烧录所遇到的问题
  10. 内网通3.4.3045版本 免广告码 积分码 算法
  11. C/C++语言经典、实用、趣味程序设计编程百例精解
  12. SpringIOC、AOP
  13. java画板_java 画板画图程序
  14. HaLoop——适用于迭代计算的Hadoop
  15. 《中国历代著名文学家评传》目录
  16. ggplot2读书笔记9:第六章 标度(二)
  17. Android UI控件和布局
  18. 2023注册会计电子版教材
  19. 怎样把几个PDF文档合并一个文件?
  20. ERP系统的数据安全

热门文章

  1. 苹果 macbookpro m2 pro、m2 max、m1 pro和 m1 max区别
  2. 开源测试平台RunnerGo,测试工程师必备
  3. 【51CTO学院】双11抽奖规则
  4. 酷冷战神 先手致胜:腾讯ROG游戏手机6为游戏而生
  5. 拼多多员工匿名发帖被辞退,拼多多回应
  6. 【Java学习笔记1】Java概述 -背景+环境搭建
  7. 『毒舌电影社区』干掉烂片,让烂片无路可走!
  8. spring中的注解和xml配置文件中配置对应总结
  9. P4086 [USACO17DEC]My Cow Ate My Homework S(静态数据预处理:后缀和、后缀最小值)
  10. 你的微信接收消息也会延迟吗?原因居然出在这,一招教你轻松解决