引言--多看案例
STL概念
STL(Standard Template Library, 标准模板库 ), 是惠普实验室开发的一系列软件的统称。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
示例
using namespace std;
void fun01()
{
string str01;
cout<<"str01"<<str01<<endl;
// string str02("hello");
string str02("时间里的空白");
cout<<"str02="<<str02<<endl;
string str03=str02;
cout<<"str03="<<str03<<endl;
string str04(3,'A');
cout<<"str04="<<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 个字符赋给当前的字符串string& 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 个字符赋值给字符串
示例1
void fun02()
{
string str01;
cout<<"str01"<<str01<<endl;
str01="何必难为自己";
cout<<"str01"<<str01<<endl;
string str02;
str02=str01;
cout<<"str02="<<str02<<endl;
string str03;
str03='a';
cout<<"str03="<<str03<<endl;
}
示例2
void fun03()
{
// string& assign(const char *s);//把字符串s赋给当前的字符串
// string& assign(const char *s, int n);//把字符串s的前n个字符赋给当前的字符串
// string& 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个字符赋值给字符串
string str01 = "hello";
cout << "str01 = " << str01 << endl;
str01.assign("world123");
cout<<"str01="<<str01<<endl;
str01.assign("mylove159",5);//mylov
cout<<"str01="<<str01<<endl;
str01.assign(3,'h');
cout<<"str01="<<str01<<endl;
string str02;
str02.assign(str01,0,2);
cout << "str02 = " << str02 << endl;
string str03;
str03.assign(str02);
cout<<"str03:"<<str03<<endl;
}
获取字符串长度
语法
int size();
int length();
注意:不包含\0
示例
void fun04()
{
string str="hello";
int size=str.size();
cout<<"size="<<size<<endl;
int len=str.length();
cout<<"len="<<len<<endl;
}
存取字符操作
语法
char& operator[](int n);//通过[]方式取字符,下标越界不会抛出异常
char& at(int n);// 通过 at 方法获取字符 , 下标越界会抛出异常
示例
void fun05()
{
string str="hello";
cout<<str[2]<<endl;
cout<<str.at(1)<<endl;
}
拼接操作
string& operator+=(const string& str);// 重载 += 操作符string& 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 个字符 c
示例
void fun06()
{
string str01="Hi";
str01+="C++";
cout<<"str01="<<str01<<endl;
string str02="STL";
str01+=str02;
cout<<"str01="<<str01<<endl;
str01+='A';
cout<<"str01="<<str01<<endl;
}
void fun07()
{
// string& append(const char *s);
//把字符串s连接到当前字符串结尾
string str01;
str01.append("hi");
cout<<"str01="<<str01<<endl;
str01.append("C++");
cout<<"str01="<<str01<<endl;
// string& append(const char *s, int n);
//把字符串s的前n个字符连接到当前字符串结尾
string str02;
str02.append("ggbang",5);
cout<<"str02="<<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="<<str04<<endl;
// string& append(int n, char c);
//在当前字符串结尾添加n个字符c
str04.append(2,'p');
cout<<"str04="<<str04<<endl;
}
查找和替换
语法
int find(const string& str, int pos = 0) const; // 查找 str 第一次出现位置 ,从 pos 开始查找int find(const char* s, int pos = 0) const; // 查找 s 第一次出现位置 , 从 pos开始查找int find(const char* s, int pos, int n) const; // 从 pos 位置查找 s 的前 n 个字符第一次位置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 个字符最后一次位置int rfind(const char c, int pos = 0) const; // 查找字符 c 最后一次出现位置string& replace(int pos, int n, const string& str); // 替换从 pos 开始 n 个字符为字符串 strstring& replace(int pos, int n, const char* s); // 替换从 pos 开始的 n 个字符为字符串 s注意 : 查找是不存在返回 -1
示例
void fun08()
{
string str="456love456";
int i01=str.find('4');
cout<<"i01="<<i01<<endl;
int i02=str.rfind('4');
cout<<"i02="<<i02<<endl;
int i03=str.find("6l");
cout<<"i03="<<i03<<endl;
str.replace(3,3,"15587554");
cout<<"str="<<str<<endl;
}
比较操作
/***compare 函数在 > 时返回 1 , < 时返回 -1 , == 时返回 0 。* 比较区分大小写,比较时参考字典顺序,排越前面的越小。大写的 A 比小写的 a 小。**/int compare(const string &s) const;// 与字符串 s 比较int compare(const char *s) const;// 与字符串 s 比较
截取操作
语法
string substr(int pos = 0, int n = npos) const;// 返回由 pos 开始的 n 个字符组成的字符串
示例
void fun09()
{
string str01="a.txt";
string str03="baby.go";
string str02=str01.substr(1,4);
string str04=str03.substr(1,3);
cout<<str02<<endl;
cout<<str04<<endl;
}
插入与删除
语法
string& insert(int pos, const char* s); // 插入字符串string& insert(int pos, const string& str); // 插入字符串string& insert(int pos, int n, char c);// 在指定位置插入 n 个字符 cstring& erase(int pos, int n = npos);// 删除从 Pos 开始的 n 个字符
示例
void fun10()
{
// 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 str01 = "11";
//开始位置不要超出字符串下标范围
// str01.insert(1,"abc");
str01.insert(1,3,'A');
cout << "str01 = " << str01 << endl;
// string& erase(int pos, int n = npos);//删除从Pos开始的n个字符
str01.erase(1,3);
cou
string与char* 转换
//string转char*
string str="itcast";
const char* cstr=str.c_str();
//char*转string
char* s="itcast";
string str(s);
示例
void fun11()
{
string str01 = "abc";
string str02("abc");
cout<<str02<<endl;
char* str03 = (char* )str01.c_str();
cout<<str03<<endl;
}
重要案例
//解析字符串
void fun13()
{
string str="www.itcast.com.cn";
vector<string> v;
int start=0;
int pos=-1;
while (true)
{
//www.itcast.com.cn
pos=str.find(".",start);
if (pos==-1)
{
//将cn截取出来
string tempStr=str.substr(start,str.size()-start);
v.push_back(tempStr);
start=pos+1;
break;
}
string tempStr=str.substr(start,pos-start);
v.push_back(tempStr);
start=pos+1;
}
for (vector<string>::iterator it=v.begin();it!=v.end();it++)
{
cout<<*it<<endl;
}
}
/*
写一个函数,函数内部将string字符串中所有的小写字母都变成大写字母
*/
void fun14()
{
string str="abcDEF";
for (int i = 0; i < str.size(); i++)
{
// str[i]=toupper(str[i]);//全部转大写
str[i]=tolower(str[i]);//全部转小写
}
cout<<str<<endl;
}
Vector
概述
连续开辟 , 单向开口 , 随机访问迭代器 , 有容量 , 每次扩容是原来的 2 倍底层数据结构 : 数组
与数组区别
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(6);//尾部添加
v01.push_back(5);
v01.push_back(12);
vector<int> v02(v01.begin()+1,v01.begin()+2);//包含开始位置,不包含结束位置(前闭后开)
//vector<int>::iterator it=v02.begin();
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()
{
// assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。
// assign(n, elem);//将 n 个 elem 拷贝赋值给本身。
// vector& operator=(const vector &vec);//重载等号操作符
// swap(vec);// 将 vec 与本身的元素互换
vector<int> v01;
v01.push_back(1);
v01.push_back(6);
v01.push_back(9);
v01.push_back(1);
v01.push_back(3);
v01.push_back(4);
vector<int> v02;
// v02.assign(v01.begin(),v01.begin()+3);
// v02.assign(5,3);
// v02 = v01;
v02.push_back(2);
v02.push_back(4);
v02.swap(v01);
auto it=v02.begin();
while (it!=v02.end())
{
cout<<*it<<endl;
it++;
}
cout<<"-------------"<<endl;
auto it01=v01.begin();
while (it01!=v01.end())
{
cout<<*it01<<endl;
it01++;
}
}
插入与删除
语法
push_back(ele); // 尾部插入元素 eleinsert(const_iterator pos, int count, 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); //尾部插入元素 ele
v.push_back(1);
v.push_back(3);
v.push_back(6);
v.push_back(7);
v.push_back(9);
// insert(const_iterator pos, int count, T ele); //迭代器指向位置 pos 插入count个元素ele.
v.insert(v.begin(),4,0);
// 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.clear();
// 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(12);
v.push_back(7);
v.push_back(6);
v.push_back(2);
// 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 ,若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。void resize(int num, elem); // 重新指定容器的长度为 num ,若容器变长,则以elem 值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。int capacity(); // 容器的容量void reserve(int len); // 容器预留 len 个元素长度
示例
void fun07()
{
vector<int> v;
v.push_back(1);
v.push_back(9);
v.push_back(6);
v.push_back(2);
v.push_back(7);
// cout<<v.size()<<endl;
// int size(); // 返回容器中元素的个数
cout<<v.empty()<<endl;
// bool empty(); //判断容器是否为空, 返回bool值(0, 1)
void resize(int num);
// 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;
}
存储自定义类型
示例
void fun09()
{
vector<Per> ps;
ps.push_back(Per("张三"));
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);
v1.push_back(60);
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==int
cout<<*mit<<"";
}
cout<<endl;
}
}
重要案例
void fun11()
{
vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(50);
v.push_back(60);
//逆序遍历
for (vector<int>::reverse_iterator it=v.rbegin();it!=v.rend();it++)
{
cout<<*it<<endl;
}
//vector的迭代器是随机访问迭代器,支持跳跃访问
vector<int>::iterator itBegin=v.begin();
itBegin=itBegin+3;
cout<<*itBegin<<endl;
}
deque
概述
deque 则是一种双向开口的连续线性空间。所谓的双向开口,意思是可以在头尾两端分别做元素的插入和删除操作数据结构 : 数组
与vector的区别
一在于 deque 允许使用常数项时间对头端进行元素的插入和删除操作。
二在于 deque 没有容量的概念,因为它是动态的以分段连续空间组合而成,随时可以增加一段新的空间并链接起来
api
// 构造函数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
概念
栈(先进后出,又名水桶),单向开口,没有迭代器
api
构造函数stack<T> stkT;//stack 采用模板类实现, stack 对象的默认构造形式:stack(const stack &stk);// 拷贝构造函数赋值操作stack& operator=(const stack &stk);// 重载等号操作符数据存取操作push(elem);// 向栈顶添加元素pop();// 从栈顶移除第一个元素top();// 返回栈顶元素大小操作empty();// 判断堆栈是否为空size();// 返回堆栈的大小
示例
void fun01()
{
stack<int> s;
//入栈
s.push(10);
s.push(20);
s.push(30);
s.push(40);
while (!s.empty())
{
//访问栈顶元素
cout<<s.top()<<endl;
//出栈
s.pop();
}
cout<<"size="<<s.size()<<endl;
}
queue
概念
队列 ( 先进先出 ), 又名水管 , 双向开口 , 没有迭代器队头 : 出数据队尾 : 入数据
api
构造函数queue<T> queT;//queue 采用模板类实现, queue 对象的默认构造形式:queue(const queue &que);// 拷贝构造函数存取、插入和删除操作push(elem);// 往队尾添加元素pop();// 从队头移除第一个元素back();// 返回最后一个元素front();// 返回第一个元素赋值操作queue& operator=(const queue &que);// 重载等号操作符大小操作empty();// 判断队列是否为空size();// 返回队列的大小
示例
#include<iostream>
#include<queue>
#include<string>
using namespace std;
class Person
{
public:
Person(string name,int age)
{
this->m_Name=name;
this->m_Age=age;
}
string m_Name;
int m_Age;
};
void fun01()
{
queue<Person> Q;//队列容器
Person p1("张三",18);
Person p2("李四",10);
Person p3("王五",12);
Person p4("赵六",28);
Person p5("二狗",30);
//入队
Q.push(p1);
Q.push(p2);
Q.push(p3);
Q.push(p4);
Q.push(p5);
cout<<"size="<<Q.size()<<endl;
while (!Q.empty())
{
cout<<"队头元素--姓名"<<Q.front().m_Name<<"年龄:"<<Q.front().m_Age<<endl;
cout<<"队尾元素--姓名"<<Q.back().m_Name<<"年龄:"<<Q.back().m_Age<<endl;
//出队
Q.pop();
}
cout<<"size="<<Q.size()<<endl;
}
int main(int argc, char const *argv[])
{
fun01();
return 0;
}
list
概念
基于双向链表的 , 离散存储的 , 双向迭代器 , 元素可重复数据结构 : 链表双向迭代器 : 可以 ++,--, 但是不能 +,-,不支持随机访问
api
构造函数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 排序
示例
//遍历链表
void printList(list<int> & L)
{
for (list<int>::iterator it=L.begin();it!=L.end();it++)
{
cout<<*it<<endl;
}
}
void fun01()
{
list<int> nums;
nums.push_back(1);
nums.push_back(5);
nums.push_back(3);
nums.push_back(7);
nums.reverse();
printList(nums);
}
void fun02()
{
list<int> nums;
nums.push_back(1);
nums.push_back(5);
nums.push_back(3);
nums.push_back(7);
nums.sort();
printList(nums);
}
void fun03()
{
list<int> nums;
nums.push_back(1);
nums.push_back(5);
nums.push_back(3);
nums.push_back(7);
nums.sort();
nums.reverse();
printList(nums);
}
void fun04()
{
list<int> nums;
nums.push_back(1);
nums.push_back(5);
nums.push_back(3);
nums.push_back(7);
printList(nums);
cout<<"-------------"<<endl;
nums.push_front(22);
nums.push_front(33);
nums.push_front(66);
printList(nums);
cout<<"-------------"<<endl;
nums.pop_back();//尾删
nums.pop_front();//头删
printList(nums);
cout<<"-------------"<<endl;
//插入
nums.insert(nums.begin(),8888);
printList(nums);
cout<<"-------------"<<endl;
nums.erase(nums.begin());
printList(nums);
cout<<"-------------"<<endl;
//remove 直接删除数组内该元素,将一样的也一起删除
nums.push_back(22);
nums.push_back(22);
nums.remove(22);
nums.remove(33);
printList(nums);
}
//遍历链表
void printList(list<int> & L)
{
for (list<int>::iterator it=L.begin();it!=L.end();it++)
{
cout<<*it<<endl;
}
}
bool myCompare(int v1,int v2)
{
return v1>v2;
}
void fun05()
{
list<int> L;
L.push_back(10);
L.push_back(20);
L.push_back(30);
L.push_front(100);
L.push_front(200);
L.push_front(300);
//反转
L.reverse();
printList(L);
cout<<"----------------"<<endl;
//排序 如果容器的迭代器支持随机访问,可以使用系统提供的标志算法
//不支持随机访问的迭代器容器,内部会提供对应的算法接口
//sort(L.begin(),L.end());
L.sort(myCompare);
printList(L);
}
//遍历链表
void printList(list<int> & L)
{
for (list<int>::iterator it=L.begin();it!=L.end();it++)
{
cout<<*it<<endl;
}
}
class Person
{
public:
Person(string name,int age,int height)
{
this->m_Name=name;
this->m_Age=age;
this->m_Height=height;
}
bool operator==(const Person & p)
{
if (this->m_Name==p.m_Name&&this->m_Age==p.m_Age&&this->m_Height==p.m_Height)
{
return true;
}
return false;
}
string m_Name;
int m_Age;
int m_Height;
};
bool myComparePerson(Person &p1,Person &p2)
{
if (p1.m_Age==p2.m_Age)
{
return p1.m_Height<p2.m_Height;
}
return p1.m_Age>p2.m_Age;
}
void fun06()
{
list<Person> L;
Person p1("王尼玛",17,178);
Person p2("法外狂徒",27,153);
Person p3("李大奔",22,168);
Person p4("沙巴特",44,172);
Person p5("杀马特",5,145);
Person p6("狗哥",36,197);
Person p7("刘备",26,170);
Person p8("关羽",26,217);
Person p9("张飞",26,194);
L.push_back(p1);
L.push_back(p2);
L.push_back(p3);
L.push_back(p4);
L.push_back(p5);
L.push_back(p6);
L.push_back(p7);
L.push_back(p8);
L.push_back(p9);
//按照年龄进行降序 从大到小,如果年龄相等,按照身高进行升序
//对于自定义数据类型,必须要指定排序规则
L.sort(myComparePerson);
for (list<Person>::iterator it=L.begin();it!=L.end();it++)
{
cout<<"姓名:"<<(*it).m_Name<<" 年龄:"<<it->m_Age<<" 身高:"<<it->m_Height<<endl;
}
//删除杀马特
L.remove(p5);
cout<<"删除杀马特后"<<endl;
for (list<Person>::iterator it=L.begin();it!=L.end();it++)
{
cout<<"姓名:"<<(*it).m_Name<<" 年龄:"<<it->m_Age<<" 身高:"<<it->m_Height<<endl;
}
}
注意:如果利用remove删除自定义数据类型,需要重载==
set/multiset
set特点
Set 的特性是所有元素都会根据元素的键值自动被排序。set 容器的键值和实值 是同一个值。Set 不允许两个元素 有相同的键值。Set 容器的迭代器 是只读迭代器。 插入数据后 不允许修改 set 的键值。数据结构 : 红黑树注意 :如果存入的值大于原有的值 , 此时 x > y 为真 , 存入的值在原有值左边如果存储的值小于原有的值 , 此时 x > y 为假 , 交换在比较如果交换后 , 存储的值为 y, 原有值的为 x, 此时 x > y 为真 , 存入的值不应该在原有值左边如果交换后 , 存储的值为 y, 原有值的为 x, 此时 x > y 为假 , 此时证明不符合其存储原则
multiset特点
multiset 特性及用法和 set 完全相同,唯一的差别在于它允许键值重复。数据结构 : 红黑树
api
构造函数
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 相等的上下限的两个迭代器。
示例
void printSet(set<int>&s)
{
for (set<int>::iterator it=s.begin();it!=s.end();it++)
{
cout<<*it<<endl;
}
}
void fun01()
{
set<int>s;
s.insert(10);
s.insert(30);
s.insert(20);
s.insert(40);
s.insert(90);
s.insert(60);
printSet(s);
if (s.empty())
{
cout<<"set容器为空"<<endl;
}
else
{
cout<<"set容器不为空 大小为:"<<s.size()<<endl;
}
s.erase(40);
printSet(s);
}
void fun02()
{
set<int>s;
s.insert(10);
s.insert(30);
s.insert(20);
s.insert(40);
s.insert(90);
s.insert(60);
set<int>::iterator pos=s.find(30);
if (pos!=s.end())
{
cout<<"找到了元素"<<*pos<<endl;
}
else
{
cout<<"没找到"<<endl;
}
//对于set而言,要么0 要么1
int num=s.count(40);
cout<<"key为40的个数为:"<<num<<endl;
//lower_bound(keyElem);//返回第一个key>=keyElem元素的迭代器
set<int>::iterator pos2=s.lower_bound(30);
if (pos2!=s.end())
{
cout<<"lower_bound的值为:"<<*pos2<<endl;
}
else
{
cout<<"未找到"<<endl;
}
//upper_bound(keyElem);//返回第一个key>keyElem元素的迭代器
pos2=s.upper_bound(30);
if (pos2!=s.end())
{
cout<<"lower_bound的值为:"<<*pos2<<endl;
}
else
{
cout<<"未找到"<<endl;
}
//equal_range(keyElem);//返回容器中key与keyElem相等的上下限的两个迭代器
pair<set<int>::iterator,set<int>::iterator>ret=s.equal_range(30);
if (ret.first!=s.end())
{
cout<<"equal_range中的lower_bound的值为:"<<*ret.first<<endl;
}
if (ret.second!=s.end())
{
cout<<"equal_range中的upper_bound的值为:"<<*ret.second<<endl;
}
}
map/multimap
map概述
键值对的形式存储数据,一个键值对称为一个对组
这一对值可以具有不同的数据类型,两个值可以分别用 pair( 对组 ) 的两个公共的成员变量 first( 键 ) 和 second( 值 ) 访问。不允许键重复
multimap概述
允许键重复
api
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 相等的上下限的两个迭代器。
示例
void fun01()
{
map<int,int>m;
//第一种插入方式
m.insert(pair<int,int>(1,10));
//第二种插入方式 推荐
m.insert(make_pair(2,20));
//第三种插入方式
m.insert(map<int,int>::value_type(3,30));
//第四种
m[4]=40;
for (map<int,int>::iterator it=m.begin();it!=m.end();it++)
{
cout<<"key="<<it->first<<"value="<<it->second<<endl;
}
cout<<"------------"<<endl;
m.erase(3);//删除传入key的值
for (map<int,int>::iterator it=m.begin();it!=m.end();it++)
{
cout<<"key="<<it->first<<"value="<<it->second<<endl;
}
}
void fun02()
{
map<int,int>m;
//第一种插入方式
m.insert(pair<int,int>(1,10));
//第二种插入方式 推荐
m.insert(make_pair(2,20));
//第三种插入方式
m.insert(map<int,int>::value_type(3,30));
//第四种
m[4]=40;
map<int,int>::iterator ret=m.find(3);
if (ret!=m.end())
{
cout<<"找到了key为"<<ret->first<<"value="<<ret->second<<endl;
}
else
{
cout<<"未找到"<<endl;
}
int num=m.count(4);
cout<<"key为4的对组个数为:"<<num<<endl;
//lower_bound(keyElem);//返回第一个key>=keyElem元素的迭代器
map<int,int>::iterator pos=m.lower_bound(3);
if (pos!=m.end())
{
cout<<"找到了lower_bound key:"<<pos->first<<"value="<<pos->second<<endl;
}
else
{
cout<<"未找到"<<endl;
}
//upper_bound(keyElem);//返回第一个key>keyElem元素的迭代器
pos=m.upper_bound(3);
if (pos!=m.end())
{
cout<<"找到了upper_boun key:"<<pos->first<<"value="<<pos->second<<endl;
}
else
{
cout<<"未找到"<<endl;
}
//equal_range(keyElem);//返回容器中key与keyElem相等的上下限的两个迭代器
pair<map<int,int>::iterator,map<int,int>::iterator> ret2=m.equal_range(3);
if (ret2.first!=m.end())
{
cout<<"找到了equal_range中的lower_bound的key="<<ret2.first->first<<"value="<<ret2.first->second<<endl;
}
else
{
cout<<"未找到"<<endl;
}
if (ret2.second!=m.end())
{
cout<<"找到了equal_range中的upper_boun的key="<<ret2.second->first<<"value="<<ret2.second->second<<endl;
}
else
{
cout<<"未找到"<<endl;
}
}
class myCompareInt
{
public:
bool operator()(int v1,int v2)
{
return v1>v2;
}
};
void fun03()
{
map<int,int,myCompareInt>m;
//第一种插入方式
m.insert(pair<int,int>(1,10));
//第二种插入方式 推荐
m.insert(make_pair(2,20));
//第三种插入方式
m.insert(map<int,int>::value_type(3,30));
//第四种
m[4]=40;
for (map<int,int,myCompareInt>::iterator it=m.begin();it!=m.end();it++)
{
cout<<"key="<<it->first<<"value="<<it->second<<endl;
}
}
总结
vector 单端动态数组 随机访问迭代器 (重点)
比如软件历史操作记录的存储,我们经常要查看历史记录,比如上一次的记录,上上次的记录,但却不会去删除记录,因为记录是事实的描述。数据结构 : 数组deque :双端动态数组 随机访问迭代器deque 的使用场景:比如排队购票系统,对排队者的存储可以采用 deque ,支持头端的快速移除,尾端的快速添加stack 栈容器 没有迭代器 先进后出queue 队列容器 没有迭代器 先进先出list 链表容器 双向迭代器 ( 重点 )比如公交车乘客的存储,随时可能有乘客下车,支持频繁的不确实位置元素的移除插入数据结构 : 双链表set 容器 只有键值 键值不能重复 自动排序 只读迭代器比如对手机游戏的个人得分记录的存储,存储要求从高 分到低分的顺序排列。数据结构 : 红黑树map 容器: 键值 - 实值成对出现 键值不能重复 自动排序 只读迭代器 ( 重点 )比如按 ID 号存储十万个用户,想要快速要通过 ID 查找对应的用户。数据结构 : 红黑树
评委打分案例
#include<iostream>
#include<vector>
#include<string>
#include<deque>
#include<stdlib.h>
#include<algorithm>
#include<time.h>
using namespace std;
/*
有5名选手:选手ABCDE,10个评委分别对每一名选手打分,去除最高分,去除评委中最低分,取平均分
1.创建5名选手,放到vector中
2.遍历vector容器,取出每一个选手,执行for循坏,可以把10个评分打分存到deque容器中
3.sort算法对deque容器中分数排序,pop_back pop_front去除最高和最低分
4.deque容器遍历一遍,累加分数,累加分数/d.size()
5.person.score=平均分
*/
class Player
{
public:
Player(string name,int score)
{
this->m_Name=name;
this->m_Score=score;
}
string m_Name;//姓名
int m_Score;//平均分
};
void createPlayer(vector<Player>&v) //必须用引用的方式接收
{
string nameSeed="ABCDE";
for(int i=0;i<5;i++)
{
string name="选手";
name+=nameSeed[i];
int score=0;
Player player(name,score);
v.push_back(player);
}
}
void setScore(vector<Player>&v)
{
for (vector<Player>::iterator it=v.begin();it!=v.end();it++)
{
deque<int>d;//存放评委打分的容器
for (int i = 0; i < 10; i++)
{
int score=rand()%41+60;//60~100
d.push_back(score);
}
cout<<it->m_Name<<"打分情况"<<endl;
for (deque<int>::iterator dit=d.begin();dit!=d.end();dit++)
{
cout<<*dit<<" ";
}
cout<<endl;
//排序
sort(d.begin(),d.end());
//去除最高最低分
d.pop_back();//最高分
d.pop_front();//最低分
//总分
int sum=0;
for (deque<int>::iterator dit=d.begin();dit!=d.end();dit++)
{
sum+=*dit;
}
//平均分
int avg=sum/d.size();
it->m_Score=avg;
}
}
void showScore(vector<Player> &v)
{
for (vector<Player>::iterator it=v.begin();it!=v.end();it++)
{
cout<<"姓名:"<<(*it).m_Name<<" 平均分数:"<<(*it).m_Score<<endl;
}
}
int main(int argc, char const *argv[])
{
//设置随机数种子
srand((unsigned int)time(NULL));
//1.创建5名选手
vector<Player> v;
createPlayer(v);
//2.打分
setScore(v);
//3.显示平均分
showScore(v);
// for (vector<Player>::iterator it=v.begin();it!=v.end();it++)
// {
// cout<<"姓名:"<<(*it).m_Name<<" 分数:"<<(*it).m_Score<<endl;
// }
return 0;
}