STL
STL是标准模板库,是惠普实验室开发的一系列软件的统称
STL的6大组件
容器 算法 迭代器 仿函数 适配器 空间适配器
容器
作用:容纳存储的数据
分类:
序列式容器:
强调值的顺序,每个元素均有固定的位置,除非用删除或插入的操作改变这个位置,如vector,deque/queue,list;
关联式容器:
非线性,为二叉树结构,各元素之间没有严格的物理上的顺序关系
在数据中选择一个关键字key,这个key对数据起到索引的作用,方便查找
如: set/multiset, map/multimap 容器
注意:
容器可以嵌套容器
算法
作用:操作数据,如插入数据,删除数据,修改数据,排序等
分类:
质变算法:是指运算过程中可以改变区间内的元素内容,如拷贝,替换,删除等
非质变算法:是指运算过程中不会更改区间内的元素内容,例如查找,计数,遍历,寻找极值等
迭代器
作用:容器与算法之间的粘合剂
注意:每个容器都有自己的迭代器
分类:
输入迭代器,提供对数据的只读访问,只读,支持++ == ! =
输出迭代器,提供对数据的只写访问,只写,支持++
前向迭代器,提供读写操作,并能向前推进迭代器,读写,支持++ == ! =
双向迭代器,提供读写操作,并能向前向后操作,读写,支持++ --
随机访问迭代器,提供读写操作,并能以跳跃的方式访问容器的任意数据,是功能最强的迭代器读写,支持++ -- [n] - n < <= > >=
仿函数
作用:为算法提供策略
适配器
作用:为算法提供更多的参数接口
空间适配器
为容器和算法管理空间
常用容器
string
作用:存储字符的容器(字符串)
构造函数:
string();//创建一个空的字符串 如:string str;
string(const string& str);//使用一个string对象初始化另一个string对象
string(const char* s);//使用字符串s初始化
string(int n,char c);//使用n个字符c初始化v
void fun01()
{
string str01;
cout<<"str01"<<endl;
string str02("hello");
cout<<"str02"<<endl;
string str03 = str02;
cout<<"str03"<<endl;
string str04(3,'a');
cout<<"str04"<<endl;
}
基本赋值操作
string& operator=(const char* s);//char类型字符串赋值给当前的字符串
string& operator=(const string &s);//把字符串s赋给当前的字符串
string& operator=(char c);//将字符赋值给当前字符串
string& assign(const char *s);//把字符串s赋值给当前的字符串
string& assign(const char *s,int n);//把字符串s的前n个字符赋值给当前的字符串
srting& assign(const string &s);//把字符串s赋值给当前字符串
string& assign(int n,char c);//用n个字符c赋给当前字符串
string& assign(const string &s,int start,int n);//将s从start开始的n个字符赋值给字符串
获取字符串长度
语法:
字符串.size()
字符串.length();
注意:
不包含\0
void fun()
{
string str = "hello";
int size = str.size();
cout<<size<<endl;
int len = str.length();
cout<<len<<endl;
}
存取字符操作
语法:
char& operator[](int n);//通过[]方式取字符串,下标越界不会抛出异常
char& at(int n);//通过at方法获取字符,下标越界会抛出异常
void fun()
{
string str = "hello";
cout<<str[2]<<endl;
cout<<str.at(1)<<endl;
}
拼接操作
string& operator+=(const string& str);//重载+=操作符
srting& operator+=(const char* str);//重载+=操作符
string& operator+=(const char c);//重载+=操作符
string& append(const char *s);//把字符串s连接到当前字符串结尾
string& append(const char *s,int n);//把字符串s的前n个字符连接到当前字符串结尾
string& append(const string &s);//同operator+=()
string& append(const string &s,int pos,int n);//把字符串s中从pos开始的n个字符连接到当前字符串结尾
string& append(int n,char c);//在当前字符串结尾添加n个字符
void fun()
{
string str01 = "hi";
str01+="C++";
cout<<"str01"<<endl;
string srt02 = "STL";
str01+=str02;
cout<<str01<<endl;
str+='A';
cout<<str01<<endl;
}
void fun()
{
//string& append(const char *s);//把字符串s连接到当前字符串结尾
string str01;
str01.append("hi");
cout<<str01<<endl;
//string& append(const char *s,int n);//把字符串s的前n个字符连接到当前字符串结尾
string str02;
str02.append("asdffghj",6);
cout<<str02<<endl;
//string& append(const string &s);//同operator+=()
//string& append(const string &s,int pos,int n);//把字符串s中从pos开始的n个字符连接到当前字符串结尾
string str03 = "1234567890";
string str04;
str04.append(str03,3,2);
cout<<str04<<endl;
//string& append(int n,char c);//在当前字符串结尾添加n个字符c
str04.append(2,'w');
cout<<str04<<endl;
}
查找和替换
ps:
当在类的成员函数后面加上
const
关键字时,它表示这个成员函数是一个 “常量成员函数”。这意味着该函数不会修改它所属对象的状态(即不会修改对象的数据成员)。int find(const string& str,int pos = 0)const;//查找str第一次出现的位置,从pos开始查找
intfind(const char *s,int pos = 0)const;//查找s第一次出现的位置,从pos开始查找
int find(const char*s,int pos,int n)const;//从pos位置开始,查找字符串s中前n个字符里特定字符(假设这里查找的是字符ch,可根据实际情况调整)第一次出现的位置
int find(const char c,int pos = 0)const;//查找字符c第一次出现的位置
int rfind(const string& str,int pos = npos)const;//查找str最后一次出现的位置,从pos开始查找
int rfind(const char* s,int pos= npos)const;//查找s最后一次出现的位置,从pos开始查找
int rfind(const char*s, int pos,int n)const;//从pos位置开始,查找字符串s中前n个字符里特定字符(假设这里查找的是字符ch,可根据实际情况调整)最后一次出现的位置
string& replace(int pos,int n,const string&str);//替换从pos开始的n个字符为字符串str
string& replace(int pos,int n,const char* s);//替换从pos开始n个字符为字符串s
注意:查找不存在返回-1
void fun()
{
string str = "12345654321";
int a1 = str.find('2');
cout<<a1<<endl;
int a2 = str.find("56");
cout<<a2<<endl;
int a3 = str.rfind('2');
cout<<a3<<endl;
str.replace(3,3,"7890");
cout<<str<<endl;
}
比较操作
/*
compare函数在大于时返回1,小于时返回-1,等于时返回0
比较区分大小写,按照字典顺序,排在越前面越小,A比a小
*/
int compare(const string &s)const;//与字符串s比较
int compare(const char *s)const;//与字符串s比较
#include <iostream>
#include <string>
using namespace std;class MyString {
private:
string data;
public:
MyString(const string& str) : data(str) {}// 比较当前对象与传入的std::string类型字符串
int compare(const string& s) const {
return this->data.compare(s);
}// 比较当前对象与传入的C风格字符串(以'\0'结尾的字符数组)
int compare(const char* s) const {
return this->data.compare(s);
}
};int main() {
MyString myStr("hello");
string otherStr = "world";
const char* cStr = "hello";// 调用compare函数比较MyString对象和std::string对象
int result1 = myStr.compare(otherStr);
if (result1 < 0) {
cout << "myStr 小于 otherStr" << endl;
} else if (result1 > 0) {
cout << "myStr 大于 otherStr" << endl;
} else {
cout << "myStr 等于 otherStr" << endl;
}// 调用compare函数比较MyString对象和C风格字符串
int result2 = myStr.compare(cStr);
if (result2 < 0) {
cout << "myStr 小于 cStr" << endl;
} else if (result2 > 0) {
cout << "myStr 大于 cStr" << endl;
} else {
cout << "myStr 等于 cStr" << endl;
}return 0;
}
截取操作
语法:
string substr(int pos = 0,int n= npos)const;
//返回由pos开始的n个字符组成的字符串
void fun()
{
string str01="a.txt";
string str02 = str01.substr(1,4);
cout<<str02<<endl;
}
插入与删除
语法:
string& insert(int pos,const char* s);//指定位置插入字符串
string& insert(int pos,const string& str);//指定位置插入字符串
string& insert(int pos,int n,char c);//在指定位置插入n个字符c
string& erase(int pos,int n = npos);//删除从pos开始的n个字符
void fun()
{
string str01 = "11";
str01.insert(1,3,'A');
cout<<str01<<endl;
str01.erase(1,3);//删除从pos开始的n个字符
cout<<str01<<endl;
}
string与char*转换
语法:
string
转char*
最常用的是
c_str()
函数,它返回一个const char*
指针,指向string
对象内部以'\0'
结尾的字符数组,但内容是常量。例如:const char* cstr = str.c_str();
。
data()
函数也能返回字符数组指针,和c_str()
类似,但对结尾'\0'
的保证稍弱。如const char* cstr = str.data();
。若要修改内容,可以把
string
内容复制到新的char
数组,如通过strcpy
函数:char char_array[100]; std::strcpy(char_array, str.c_str());
char*
转string
简单的方式是直接初始化或赋值。例如:
char* cstr = "Hello"; std::string str1(cstr);
或者std::string str2; str2 = cstr;
。也可以利用
string
的构造函数进行转换,还能指定字符范围等,如std::string str(cstr, 0, 5);
vector
连续开辟,单向开口,随机访问迭代器,有容量,每次扩容是原来的两倍
底层数据结构:数组
与数组的区别:vector的结构类同于数组,数组是静态的,大小是在定义时确定的
而vector是动态的,添加元素时如果空间不足时,则会自动扩容(2^n);这被称为vector的未雨绸缪机制
整体来说,vector比较灵活,而且vector是类模版,可以存放任意类型的元素
迭代器
构造函数
语法:
vector<T> v;//采用模版类实现,默认构造函数
vector(v.begin(),v.end());//将v[begin(),end()]区间中的元素拷贝给本身
vector(n,elem);//构造函数将n个elem拷贝给本身
vector(const vector &vec);//拷贝构造函数
void fun01()
{
vector<int> v01;
v01.push_back(1);//尾部添加
v01.push_back(5);
v01.push_back(3);
vector<int>::iterator it = v01.begin();//获取开始位置的迭代器
while(it != v01.end()) //end():结束的位置
{
cout<< *it <,endl; //*it获取当前迭代器指向的位置的值
it++;//迭代器后移1位
}
}
void fun02()
{
vector<int> v01;
v01.push_back(1);//尾部添加
v01.push_back(5);
v01.push_back(3);
vector<int> v02(v01.begin()+1,v01.begin()+2);//包含开始位置,不包含结束位置(前闭后开)auto it = v02.begin();//C++11及以上版本,编译时需加-std = c+=11
while(it != v02.end())
{
cout<<*it<<endl;
it++;
}
}
void fun03()
{
vector<int> v(10,5);
auto it = v.begin();
while(it !=v.end())
{
cout<<*it<<endl;
it++;
}
}
赋值操作
assign(beg,end); //将[beg,end)区间中的数据拷贝赋值给本身
assign(n,elem); 将n个elem拷贝赋值给本身
vector& operator=(const vector &vec); // 重载等号操作符
swap(vec); //将vec与本身的元素互换
void fun04()
{
vector<int> v01;
v01.push_back(1);
v01.push_back(5);
v01.push_back(3);
v01.push_back(9);
v01.push_back(7);
vector<int> v02;
v02.push_back(2);
v02.push_back(4);
v02.swap(v01);
auto it = v02.begin();
while(it != v02.end())
{
cout<<*it<<endl;
it++;
}
auto it01 = v01.begin();
while(it01 != v01.end())
{
cout<<*it01<<endl;
it01++;
}
}
插入与删除
push_back(ele); //尾部插入元素ele
insert(const_iterator pos,int cout,T ele); //迭代器指向位置pos插入count个元素ele
pop_back(); //删除最后一个元素
erase(const_iterator start,const_iterator end); //删除迭代器从start到end之间的元素,删除[start,end)区间的所有元素
erase(const_iterator pos);//删除迭代器指向的元素
clear(); //删除容器中所有元素
void fun05(){vector<int> v;// push_back(ele); //尾部插入元素 elev.push_back(1);v.push_back(3);v.push_back(5);v.push_back(7);// insert(const_iterator pos, int count, T ele); //迭代器指向位置pos 插入 count 个元素 ele.v.insert(v.begin(),1,0);// pop_back();//删除最后一个元素v.pop_back();//v.pop_back();// erase(const_iterator start, const_iterator end); //删除迭代器从start 到 end 之间的元素 , 删除 [start, end) 区间的所有元素v.erase(v.begin()+1,v.begin()+3);// erase(const_iterator pos); //删除迭代器指向的元素v.erase(v.begin());// clear(); //删除容器中所有元素v.clear();auto it = v.begin();while(it != v.end()){cout << *it << endl;it++;}}
取值操作
at(int idx); //返回索引idx所指的数据,如果idx越界,抛出out_of_range异常
operator[](int idx); // 返回索引idx所指的数据,越界时,不会直接报错
front(); //返回容器中第一个数据元素
back(); //返回容器中最后一个数据元素
void fun06()
{
vector<int> v;
v.push_back(1);v.push_back(3);v.push_back(5);v.push_back(7);// at(int idx); //返回索引 idx 所指的数据,如果 idx 越界,抛出out_of_range 异常。cout << "v.at(3) = " << v.at(3) << endl;// operator[](int idx); //返回索引 idx 所指的数据,越界时,不会报错cout << "v[2] = " << v[100] << endl;// front(); //返回容器中第一个数据元素cout << v.front() << endl;// back(); //返回容器中最后一个数据元素cout << v.back() << endl;}
大小相关
int size(); //返回容器中元素的个数
bool empty(); //判断容器是否为空,返回bool值(0,1)
void resize(int num); //重新指定的长度为num,若容器变长,则以默认值填充新位置,如果容器变短,则末尾超出容器的长度被删除
int capacity(); //容器的容量
void reserve(int len); //容器预留len个元素长度
void fun07(){vector<int> v;v.push_back(1);v.push_back(3);v.push_back(5);v.push_back(7);v.push_back(9);// int size(); // 返回容器中元素的个数// cout << v.size() << endl;// bool empty(); //判断容器是否为空, 返回 bool 值( 0 , 1 )// cout << v.empty() << endl;// void resize(int num); //重新指定容器的长度为 num ,若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。// v.resize(2);// void resize(int num, elem); //重新指定容器的长度为 num ,若容器变长,则以 elem 值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。// v.resize(10,10);// int capacity(); //容器的容量cout << v.capacity() << endl;// void reserve(int len); //容器预留 len 个元素长度v.reserve(10);cout << v.capacity() << endl;// auto it = v.begin();// while(it != v.end())// {// cout << *it << endl;// it++;// }}void fun08(){vector<int> v;v.push_back(1);v.push_back(3);v.push_back(5);v.push_back(7);v.push_back(9);cout << "v的大小 = " << v.size() << endl;cout << "v的容量 = " << v.capacity() << endl;vector<int>(v).swap(v);cout << "v的大小 = " << v.size() << endl;cout << "v的容量 = " << v.capacity() << endl;}
存储自定义类型
class Per
{
public:
Per(char *name)
{
this->name = name;
}
};
void fun09()
{
vector <Per> ps;
ps.push_back(Per("张三"));
ps.push_back(Per("李四"));
ps.push_back(Per("王五"));
for(auto it = ps.begin(); it != ps.end(); it++)
{
cout<<(*it).name<<endl;
}
}
容器嵌套
void fun10(){vector<int> v1;v1.push_back(10);v1.push_back(20);v1.push_back(30);v1.push_back(40);v1.push_back(50);vector<int> v2;v2.push_back(100);v2.push_back(200);v2.push_back(300);v2.push_back(400);v2.push_back(500);vector<int> v3;v3.push_back(1000);v3.push_back(2000);v3.push_back(3000);v3.push_back(4000);v3.push_back(5000);vector<vector<int>> v;v.push_back(v1);v.push_back(v2);v.push_back(v3);vector<vector<int>>::iterator it=v.begin();for(;it!=v.end();it++){//*it == vector<int>vector<int>::iterator mit=(*it).begin();for(;mit!=(*it).end(); mit++){//*mit==intcout<<*mit<<" ";}cout<<endl;}}
deque
deque是一种双向开口的连续线性空间,所谓的双向开口,意思是可以在头尾两端分别做元素的插入和删除操作
数据结构:数组
与vector的区别:
1,deque允许使用常数项时间对头端进行元素的插入和删除
2,deque没有容量的概念,因为他是动态的以分段连续空间组合而成,随时可以增加一段新的空间并连接起来
// 构造函数deque<T> deqT;// 默认构造形式deque(beg, end);// 构造函数将 [beg, end) 区间中的元素拷贝给本身。deque(n, elem);// 构造函数将 n 个 elem 拷贝给本身。deque(const deque &deq);// 拷贝构造函数// 赋值操作assign(beg, end);// 将 [beg, end) 区间中的数据拷贝赋值给本身。assign(n, elem);// 将 n 个 elem 拷贝赋值给本身。deque& operator=(const deque &deq); // 重载等号操作符swap(deq);// 将 deq 与本身的元素互换// 大小操作deque.size();// 返回容器中元素的个数deque.empty();// 判断容器是否为空deque.resize(num);// 重新指定容器的长度为 num, 若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。deque.resize(num, elem); // 重新指定容器的长度为 num, 若容器变长,则以 elem值填充新位置 , 如果容器变短,则末尾超出容器长度的元素被删除。// 双端插入和删除操作push_back(elem);// 在容器尾部添加一个数据push_front(elem);// 在容器头部插入一个数据pop_back();// 删除容器最后一个数据pop_front();// 删除容器第一个数据// 数据存取at(idx);// 返回索引 idx 所指的数据,如果 idx 越界,抛出 out_of_range 。operator[];// 返回索引 idx 所指的数据,如果 idx 越界,不抛出异常,直接出错。front();// 返回第一个数据。back();// 返回最后一个数据// 插入操作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 位置的数据,返回下一个数据的位置。
stack
栈(先进后出),单项开口,没有迭代器
构造函数stack<T> stkT;//stack 采用模板类实现, stack 对象的默认构造形式:stack(const stack &stk);// 拷贝构造函数赋值操作stack& operator=(const stack &stk);// 重载等号操作符数据存取操作push(elem);// 向栈顶添加元素pop();// 从栈顶移除第一个元素top();// 返回栈顶元素大小操作empty();// 判断堆栈是否为空size();// 返回堆栈的大小
queue
队列(先进先出),双向开口,没有迭代器
对头:出数据
队尾:入数据
构造函数queue<T> queT;//queue 采用模板类实现, queue 对象的默认构造形式:queue(const queue &que);// 拷贝构造函数存取、插入和删除操作push(elem);// 往队尾添加元素pop();// 从队头移除第一个元素back();// 返回最后一个元素front();// 返回第一个元素赋值操作queue& operator=(const queue &que);// 重载等号操作符大小操作empty();// 判断队列是否为空size();// 返回队列的大小
list
基于双向链表,离散存储的,双向迭代器,元素可重复
数据结构:链表
双向迭代器:可以++,--,但是不能+,-
构造函数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, 若容器变长,则以 elem 值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。赋值操作assign(beg, end);//将 [beg, end) 区间中的数据拷贝赋值给本身。assign(n, elem);//将 n 个 elem 拷贝赋值给本身。list& operator=(const list &lst);//重载等号操作符swap(lst);//将 lst 与本身的元素互换。数据的存取front();//返回第一个元素。back();//返回最后一个元素。反转排序reverse();//反转链表,比如 lst 包含 1,3,5 元素,运行此方法后, lst 就包含 5,3,1 元素。sort(); //list 排序
set/multiset
set特点
Set 的特性是。所有元素都会根据元素的键值自动被排序。set 容器的键值和实值 是同一个值。Set 不允许两个元素 有相同的键值。Set 容器的迭代器 是只读迭代器。 插入数据后 不允许修改 set 的键值。数据结构 : 红黑树注意 :如果存入的值大于原有的值, 此时 x > y 为真 , 存入的值在原有值左边如果存储的值小于原有的值, 此时 x > y 为假 , 交换在比较如果交换后, 存储的值为 y, 原有值的为 x, 此时 x > y 为真 , 存入的值不应该在原有值左边如果交换后, 存储的值为 y, 原有值的为 x, 此时 x > y 为假 , 此时证明不符合其存储原则
构造函数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概述
键值对的形式存储数据 , 一个键值对称为一个对组这一对值可以具有不同的数据类型,两个值可以分别用 pair( 对组 ) 的两个公共的成员变量 first( 键 ) 和 second( 值 ) 访问。不允许键重复
允许键重复map 构造函数map<T1, T2> mapTT;//map 默认构造函数 :T1:键的数据类型 , 要有可比较性 , 基本数据类型都有可比性T2:值的数据类型map(const map &mp);// 拷贝构造函数map 赋值操作map& operator=(const map &mp);// 重载等号操作符swap(mp);// 交换两个集合容器map 大小操作size();// 返回容器中元素的数目empty();// 判断容器是否为空map 插入数据元素操作map.insert(...); // 往容器插入元素,返回 pair<iterator,bool>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 相等的上下限的两个迭代器。
总结
vector 单端动态数组 随机访问迭代器 ( 重点 )比如软件历史操作记录的存储,我们经常要查看历史记录,比如上一次的记录,上上次的记录,但却不会去删除记录,因为记录是事实的描述。数据结构: 数组deque :双端动态数组 随机访问迭代器deque 的使用场景:比如排队购票系统,对排队者的存储可以采用 deque ,支持头端的快速移除,尾端的快速添加stack 栈容器 没有迭代器 先进后出queue 队列容器 没有迭代器 先进先出list 链表容器 双向迭代器 ( 重点 )比如公交车乘客的存储,随时可能有乘客下车,支持频繁的不确实位置元素的移除插入数据结构: 双链表set 容器 只有键值 键值不能重复 自动排序 只读迭代器比如对手机游戏的个人得分记录的存储,存储要求从高 分到低分的顺序排列。数据结构: 红黑树map 容器: 键值 - 实值成对出现 键值不能重复 自动排序 只读迭代器 ( 重点 )比如按 ID 号存储十万个用户,想要快速要通过 ID 查找对应的用户。数据结构: 红黑树