vector
/*vector容器
vector数据结构和**数组非常相似**,也称为**单端数组**
vector容器的迭代器是支持随机访问的迭代器
vector与普通数组区别:不同之处在于数组是静态空间,而vector可以**动态扩展**
动态扩展:并不是在原空间之后续接新空间,而是找更大的内存空间,然后将原数据拷贝新空间,释放原空间
v.begin() -- 指向第一个数据位置的迭代器
v.end() -- 指向最后一个数据的后一个位置的迭代器
v.rend() -- 指向第一个数据的前一个位置的迭代器
v.rbegin() -- 指向最后一个数据的位置的迭代器
v.cbegin() -- const+begin()指向第一个数据位置的常量迭代器
v.cend() -- const+end()
v.crbegin() -- const+rbegin()
v.crend() -- const+rend()
注意:begin和end换回的具体类型由对象是否是常量来决定,如果是常量,begin和end换回const_iterator;如果不是常量,换回iterator;
cbegin和cend是不管是对象本身是不是常量,换回值都是const_iterator
具有了const属性,不能用于修改元素
————————————————————————————————
vector<int> v;
const vector<int> cv;
auto it1 = v.begin(); //it1类型是vector<int>::iterator
auto it2 = cv.begin(); //it2类型是vector<int>::const_iterator
auto it3 = v.cbegin(); //it3类型是vector<int>::const_iterator
————————————————————————————————
vector构造函数
1.vector<T> v; //采用模板实现类实现,默认构造函数
2.vector(v.begin(), v.end()); //将v[begin(), end())区间中的元素拷贝给本身。
3.vector(n, elem); //构造函数将n个elem拷贝给本身
4.vector(const vector &vec); //拷贝构造函数
*/
#include<iostream>
#include<vector>
using namespace std;
void myPrintVect_1(vector<int>& v) {
for (vector<int>::iterator pBegin = v.begin(); pBegin != v.end(); pBegin++) {
cout << *pBegin << " ";
}
cout << endl;
}
void testVect_1() {
//1.默认构造 无参构造
vector<int> v1;
for (int i = 0; i < 5; i++) {
v1.push_back(i + 1);
}
myPrintVect_1(v1);
//2.通过区间的方式构造,将v[begin(), end())区间中的元素拷贝给另一个容器
vector<int> v2(v1.begin(), v1.end());
myPrintVect_1(v2);
//3.构造函数将n个elem拷贝给一个容器
vector<int> v3(5, 10);//5个10
myPrintVect_1(v3);
//4.拷贝构造
vector<int> v4(v3);
myPrintVect_1(v4);
}
//void main() {
// testVect_1();
//}
/*vector赋值操作
1.vector& operator=(const vector &vec); //重载等号操作符
2.assign(beg, end); //将[beg, end)区间中的数据拷贝赋值给本身。
3.assign(n, elem); //将n个elem拷贝赋值给本身。
*/
#include<iostream>
#include<vector>
using namespace std;
void myPrintVect_2(vector<int>& v) {
for (vector<int>::iterator pBegin = v.begin(); pBegin != v.end(); pBegin++) {
cout << *pBegin << " ";
}
cout << endl;
}
void testVect_2() {
vector<int> v;
for (int i = 0; i < 10; i++) {
v.push_back(i + 1);
}
myPrintVect_2(v);
//赋值操作
//1.重载 = 操作符
vector<int> v1;
v1=v;
myPrintVect_2(v1);
//2.assign(v.begin(), v.end())
vector<int> v2;
v2.assign(v.begin(), v.end());
myPrintVect_2(v2);
//2.assign(n, elem)
vector<int> v3;
v3.assign(10, 5);
myPrintVect_2(v3);
}
//void main() {
// testVect_2();
//}
/*vector的容量和大小
1.empty();//判断容器是否为空
2.capacity();//容器的容量
3.size();//返回容器中元素的个数
4.max_size();//返回容器可以存储的最大长度(好大好大)
5.resize(int num);//重新指定容器的长度为num,若容器变长,则以默认值填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删除。
6.resize(int num, elem);//重新指定容器的长度为num,若容器变长,则以elem值填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删除
*/
#include<iostream>
#include<vector>
using namespace std;
void myPrintVect_3(vector<int>& v) {
for (vector<int>::iterator pBegin = v.begin(); pBegin != v.end(); pBegin++) {
cout << *pBegin << " ";
}
cout << endl;
}
void testVect_3() {
vector<int> v1;
for(int i = 0; i < 10; i++) {
v1.push_back(i + 1);
}
myPrintVect_3(v1);
if (v1.empty()) {//1.empty();//判断容器是否为空
cout << "v1为空!" << endl;
}
else {
cout << "v1不为空!" << endl;
cout << "v1的容量:" << v1.capacity() << endl;//2.capacity();容器的容量
cout << "v1的长度:" << v1.size() << endl;//3.size();返回容器中元素的个数
cout << "v1的max长度:" << v1.max_size() << endl;//4.max_size();返回容器可以存储的最大长度(好大好大)
}
v1.resize(15);//5.resize(int num);//重新指定容器的长度为num,若容器变长,则以默认值填充新位置。
myPrintVect_3(v1);
v1.resize(8);//5.resize(int num);//如果容器变短,则末尾超出容器长度的元素被删除
myPrintVect_3(v1);
v1.resize(15, 5);//6.resize(int num, elem);//重新指定容器的长度为num,若容器变长,则以elem值填充新位置
myPrintVect_3(v1);
v1.resize(5, 5);//6.resize(int num, elem)//如果容器变短,则末尾超出容器长度的元素被删除
myPrintVect_3(v1);
}
//void main() {
// testVect_3();
//}
/*vector插入和删除
1.push_back(ele); //尾部插入元素ele
2.pop_back(); //删除最后一个元素
3.insert(const_iterator pos, ele);//迭代器指向位置pos插入元素ele
4.insert(const_iterator pos, int count,ele);//迭代器指向位置pos插入count个元素ele
5.insert(pos,beg,end);//在pos位置插入[beg,end)区间的数据,无返回值
6.erase(const_iterator pos);//删除迭代器指向的元素
7.erase(const_iterator start, const_iterator end);//删除迭代器从start到end之间的元素
8.clear();//删除容器中所有元素
*/
#include<iostream>
#include<vector>
using namespace std;
void myPrintVect_4(vector<int>& v) {
for (vector<int>::iterator pBegin = v.begin(); pBegin != v.end(); pBegin++) {
cout << *pBegin << " ";
}
cout << endl;
}
void testVect_4() {
vector<int> v1;
//1.push_back(ele); //尾插法
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
myPrintVect_4(v1);
//2.pop_back();//尾删法
v1.pop_back();
myPrintVect_4(v1);
//3.insert(const_iterator pos, ele);//迭代器指向位置pos插入元素ele
v1.insert(v1.begin() +3, 101);//第一个参数是迭代器,下标为3的地方插入
myPrintVect_4(v1);
//4.insert(const_iterator pos, int count, ele);//迭代器指向位置pos插入count个元素ele
v1.insert(v1.begin() + 3, 5, 100);//第一个参数是迭代器,下标为3的地方插入5个100
myPrintVect_4(v1);
//5.insert(pos,beg,end);//在pos位置插入[beg,end)区间的数据,无返回值
vector<int> v2;
v2.insert(v2.begin(), v1.begin() + 1, v1.begin() + 3);
myPrintVect_4(v2);
//6.erase(const_iterator pos);//删除迭代器指向的元素
v1.erase(v1.begin()+3);//参数是迭代器,删除下标为3的元素
myPrintVect_4(v1);
//7.erase(const_iterator start, const_iterator end);//删除迭代器从start到end之间的元素
v1.erase(v1.begin() + 1, v1.begin() + 3);//参数是迭代器,删除下标为1到3之间(下标1和2)的元素
myPrintVect_4(v1);
//8.clear();//删除容器中所有元素
v1.clear();
myPrintVect_4(v1);
cout << "v1的容量:" << v1.capacity() << endl;
cout << "v1的长度:" << v1.size() << endl;
}
//void main() {
// testVect_4();
//}
/*vector数据存取
1.at(int idx);//返回索引idx所指的数据的引用
2.operator[];//返回索引idx所指的数据的引用
3.front();//返回容器中第一个数据元素的引用
4.back();//返回容器中最后一个数据元素的引用
注意:这些函数的返回类型都是引用,函数返回类型是值时会产生一个临时变量作为函数返回值的副本,而返回引用时不会产生值的副本
返回值时对应的原始数据不可修改(修改的只是临时变量),返回引用时原始数据可以修改
*/
#include<iostream>
#include<vector>
using namespace std;
void testVect_5() {
vector<int> v1;
for (int i = 0; i < 10; i++) {
v1.push_back(i + 1);
}
//1.at(int idx);//返回索引idx所指的数据的引用
for (int i = 0; i < v1.size(); i++) {
cout << v1.at(i) << " ";
}
cout << endl;
//2.operator[];//返回索引idx所指的数据的引用
for (int i = 0; i < v1.size(); i++) {
cout << v1[i] << " ";
}
cout << endl;
//3.front();//返回容器中第一个数据元素的引用
auto &a1 = v1.front();
cout << "返回第一个元素:" << a1 << endl;
a1 = 11;//修改引用的值,就是修改原数据的值
cout << "返回第一个元素:" << v1.front() << endl;
//4.back();//返回容器中最后一个数据元素的引用
cout << "返回第最后元素:" << v1.back() << endl;
}
//void main() {
// testVect_5();
//}
/*vector互换容器——实现两个容器内元素进行互换,本质是改变指向
swap(vec);// 将vec与本身的元素互换
*/
#include<iostream>
#include<vector>
using namespace std;
void myPrintVect_6(vector<int>& v) {
for (vector<int>::iterator pBegin = v.begin(); pBegin != v.end(); pBegin++) {
cout << *pBegin << " ";
}
cout << endl;
}
void testVect_6a() {
vector<int> v1;
for (int i = 0; i < 10; i++) {
v1.push_back(i + 1);
}
vector<int> v2;
for (int i = 20; i > 0; i--) {
v2.push_back(i);
}
//v1.resize(3);
//v2.resize(5);
//swap(vec);// 将两个容器的元素互换
cout << "交换前:" << endl;
cout << "v1的容量:" << v1.capacity() << endl;
cout << "v1的大小:" << v1.size() << endl;
cout << "v2的容量:" << v2.capacity() << endl;
cout << "v2的大小:" << v2.size() << endl;
myPrintVect_6(v1);
myPrintVect_6(v2);
cout << "交换后:" << endl;
v1.swap(v2);
cout << "v1的容量:" << v1.capacity() << endl;
cout << "v1的大小:" << v1.size() << endl;
cout << "v2的容量:" << v2.capacity() << endl;
cout << "v2的大小:" << v2.size() << endl;
myPrintVect_6(v1);
myPrintVect_6(v2);
//可以看出swap()交换实质就算改变两个容器的指向
}
//巧用swap()可以收缩内存空间
void testVect_6b() {
vector<int> v;
for (int i = 0; i < 100000; i++) {
v.push_back(i + 1);
}
cout << "v的容量:" << v.capacity() << endl;
cout << "v的大小:" << v.size() << endl;
v.resize(3);//容器容量远大于容器存储的数据长度,造成内存浪费
cout << "未收缩内存空间前:" << endl;
cout << "v的容量:" << v.capacity() << endl;
cout << "v的大小:" << v.size() << endl;
//巧用swap()收缩内存空间
vector<int>(v).swap(v);
//vector<int>(v),利用拷贝构造函数创建一个匿名对象x,里面存储容器v的元素,x和v互换指向
//这一行运行完之后x指向的大容量容器被系统回收(匿名对象当前行运行完之后就被回收)
cout << "swap()收缩内存空间后:" << endl;
cout << "v的容量:" << v.capacity() << endl;
cout << "v的大小:" << v.size() << endl;
}
//void main() {
// testVect_6a();
// cout << endl << "=========巧用swap()可以收缩内存空间==========" << endl << endl;
// testVect_6b();
//}
/*vector预留空间——减少vector在动态扩展容量时的扩展次数
reserve(int len);//容器预留len个元素长度,预留位置不初始化,元素不可访问
*/
#include<iostream>
#include<vector>
using namespace std;
void testVect_7() {
vector<int> v;
v.reserve(100000);//利用reserve()可以给容器预留空间
int* p = NULL;
int num = 0;//统计开辟的次数
for (int i = 0; i < 100000; i++) {
v.push_back(i + 1);
if (p != &v[0]) {
p = &v[0];
num++;
}
}
cout << "统计开辟的次数num=" << num << endl;
}
//void main() {
// testVect_7();
//}
Deque
/*deque容器 + deque构造函数
双端数组,可以对头端进行插入删除操作,deque容器的迭代器也是支持随机访问的
deque与vector区别:
1.vector对于头部的插入删除效率低,数据量越大,效率越低
2.deque相对而言,对头部的插入删除速度回比vector快
3.vector访问元素时的速度会比deque快,这和两者内部实现有关
deque内部工作原理:
1.deque内部有个**中控器**,维护每段缓冲区中的内容,缓冲区中存放真实数据
2.中控器维护的是每个缓冲区的地址,使得使用deque时像一片连续的内存空间
deque容器构造函数:
1.deque<数据类型> deq;//默认构造形式
2.deque(beg, end);//构造函数将[beg, end)区间中的元素拷贝给本身
3.deque(n, elem);//构造函数将n个elem拷贝给本身
4.deque(const deque &deq);//拷贝构造函数
*/
#include<iostream>
#include<deque>
using namespace std;
void myPrintDeque_1(const deque<int> &deq) {//加const让引用传进来的容器只读,对应的迭代器也要改为const_iterator
for (deque<int>::const_iterator pBegin = deq.begin(); pBegin != deq.end(); pBegin++) {
cout << *pBegin << " ";
}
cout << endl;
}
void testDeque_1() {
//1.默认构造 无参构造
deque<int> deq1;
for (int i = 0; i < 10; i++) {
deq1.push_back(i);
}
myPrintDeque_1(deq1);
//2.构造函数将[beg, end)区间中的元素拷贝给本身
deque<int> deq2(deq1.begin(), deq1.end());
myPrintDeque_1(deq2);
//3.deque(n, elem);//构造函数将n个elem拷贝给本身
deque<int> deq3(10, 3);
myPrintDeque_1(deq3);
//4.deque(const deque &deq);//拷贝构造函数
deque<int> deq4(deq3);
myPrintDeque_1(deq4);
}
//void main() {
// testDeque_1();
//}
/*deque赋值操作
1.deque& operator=(const deque &deq);//重载等号操作符
2.assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。
3.assign(n, elem);//将n个elem拷贝赋值给本身。
*/
#include<iostream>
#include<deque>
using namespace std;
void myPrintDeque_2(const deque<int>& deq) {//加const让引用传进来的容器只读,对应的迭代器也要改为const_iterator
for (deque<int>::const_iterator pBegin = deq.begin(); pBegin != deq.end(); pBegin++) {
cout << *pBegin << " ";
}
cout << endl;
}
void testDeque_2() {
deque<int> deq1;
for (int i = 0; i < 10; i++) {
deq1.push_back(i);
}
myPrintDeque_2(deq1);
//赋值操作
//1.deque & operator=(const deque & deq);//重载等号操作符
deque<int> deq2;
deq2 = deq1;
myPrintDeque_2(deq2);
//2.assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身
deque<int> deq3;
deq3.assign(deq1.begin(), deq1.end());
myPrintDeque_2(deq3);
//3.assign(n, elem);//将n个elem拷贝赋值给本身。
deque<int> deq4;
deq4.assign(10, 3);
myPrintDeque_2(deq4);
}
//void main() {
// testDeque_2();
//}
/*deque大小操作
注意:deque没有容量(capacity)的概念,只有大小(size)
deque容器由于本身特性,扩容时只需要添加一个地址,不需要开辟新的空间,所以没有容量的概念
函数模型:
1.deque.empty();//判断容器是否为空
2.deque.size();//返回容器中元素的个数
3.deque.resize(num);//重新指定容器的长度为num,若容器变长,则以默认值填充新位置
//如果容器变短,则末尾超出容器长度的元素被删除。
4.deque.resize(num, elem);//重新指定容器的长度为num,若容器变长,则以elem值填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删除。
*/
#include<iostream>
#include<deque>
using namespace std;
void myPrintDeque_3(const deque<int>& deq) {//加const让引用传进来的容器只读,对应的迭代器也要改为const_iterator
for (deque<int>::const_iterator pBegin = deq.begin(); pBegin != deq.end(); pBegin++) {
cout << *pBegin << " ";
}
cout << endl;
}
void testDeque_3() {
deque<int> deq;
for (int i = 0; i < 10; i++) {
deq.push_back(i);
}
myPrintDeque_3(deq);
if (deq.empty()) {//1.deque.empty();//判断容器是否为空
cout << "deq为空" << endl;
}
else {
cout << "deq不为空" << endl;
cout << "deq的大小:" << deq.size() << endl;//2.deque.size();//返回容器中元素的个数
}
//重新指定长度
deq.resize(15);//3.deque.resize(num);
deq.resize(20, 1);//4.deque.resize(num, elem);
}
//void main() {
// testDeque_3();
//}
/*deque插入和删除
两端插入删除操作:
1.push_back(elem);//在容器尾部添加一个数据
2.push_front(elem);//在容器头部插入一个数据
3.pop_back();//删除容器最后一个数据
4.pop_front();//删除容器第一个数据
指定位置插入删除操作:
1.insert(pos,elem);//在pos位置插入一个elem元素的拷贝,返回新数据的位置
2.insert(pos,n,elem);//在pos位置插入n个elem数据,无返回值
3.insert(pos,beg,end);//在pos位置插入[beg,end)区间的数据,无返回值
4.erase(beg,end);//删除[beg,end)区间的数据,返回下一个数据的位置
5.erase(pos); //删除pos位置的数据,返回下一个数据的位置
6.clear();//清空容器的所有数据
*/
#include<iostream>
#include<deque>
#include<string>
using namespace std;
void myPrintDeque_4(const deque<string>& deq) {//加const让引用传进来的容器只读,对应的迭代器也要改为const_iterator
for (deque<string>::const_iterator pBegin = deq.begin(); pBegin != deq.end(); pBegin++) {
cout << *pBegin << " ";
}
cout << endl;
}
//两端插入删除操作
void testDeque_4a() {
deque<string> deq;
for (int i = 0; i < 10; i++) {
deq.push_back(to_string(i));
}
myPrintDeque_4(deq);
//1.push_back(elem);//在容器尾部添加一个数据
deq.push_back("尾插");
myPrintDeque_4(deq);
//2.push_front(elem);//在容器头部插入一个数据
deq.push_front("头插");
myPrintDeque_4(deq);
//3.pop_back();//删除容器最后一个数据
deq.pop_back();
myPrintDeque_4(deq);
//4.pop_front();//删除容器第一个数据
deq.pop_front();
myPrintDeque_4(deq);
}
//指定位置插入删除操作
void testDeque_4b() {
deque<string> deq;
for (int i = 0; i < 10; i++) {
deq.push_back(to_string(i));
}
myPrintDeque_4(deq);
//1.insert(pos, elem);//在pos位置插入一个elem元素的拷贝,返回新数据的位置
deq.insert(deq.begin()+3, "中间插");//pos为迭代器
myPrintDeque_4(deq);
//2.insert(pos, n, elem);//在pos位置插入n个elem数据,无返回值
deq.insert(deq.begin() + 5, 3,"中间插n个");//pos为迭代器
myPrintDeque_4(deq);
//3.insert(pos, beg, end);//在pos位置插入[beg,end)区间的数据,无返回值
deq.insert(deq.begin(), deq.begin()+5, deq.begin() + 7);//pos, beg, end都为迭代器
myPrintDeque_4(deq);
//4.erase(beg, end);//删除[beg,end)区间的数据,返回下一个数据的位置
deq.erase(deq.begin(), deq.begin() + 5);//beg, end都为迭代器
myPrintDeque_4(deq);
//5.erase(pos); //删除pos位置的数据,返回下一个数据的位置
deq.erase(deq.begin());//pos都为迭代器
myPrintDeque_4(deq);
//6.clear();//清空容器的所有数据
deq.clear();
myPrintDeque_4(deq);
}
//void main() {
// testDeque_4a();
// cout << "====================================" << endl;
// testDeque_4b();
//}
/*deque容器的存取(读写)
函数原型:
1.at(int idx);//返回索引idx所指的数据
2.operator[];//返回索引idx所指的数据
3.front();//返回容器中第一个数据元素
4.back();//返回容器中最后一个数据元素
*/
#include<iostream>
#include<deque>
using namespace std;
void myPrintDeque_5(const deque<int>& deq) {//加const让引用传进来的容器只读,对应的迭代器也要改为const_iterator
for (deque<int>::const_iterator pBegin = deq.begin(); pBegin != deq.end(); pBegin++) {
cout << *pBegin << " ";
}
cout << endl;
}
void tetsDeque_5() {
deque<int> deq;
for (int i = 0; i < 10; i++) {
deq.push_back(i);
}
myPrintDeque_5(deq);
//1.at(int idx);//返回索引idx所指的数据
cout << "deq.at(5)=" << deq.at(5) << endl;
//2.operator[];//返回索引idx所指的数据
cout << "deq[5]=" << deq[5] << endl;
//3.front();//返回容器中第一个数据元素
cout << "deq.front()=" << deq.front() << endl;
//4.back();//返回容器中最后一个数据元素
cout << "deq.back()=" << deq.back() << endl;
}
//void main() {
// tetsDeque_5();
//}
/*deque排序——利用算法实现对deque容器进行排序
sort(iterator beg, iterator end)//对beg和end区间内元素进行排序
*/
#include<iostream>
#include<deque>
#include<string>
#include<algorithm>//引入算法头文件
using namespace std;
void myPrintDeque_6(const deque<string>& deq) {//加const让引用传进来的容器只读,对应的迭代器也要改为const_iterator
for (deque<string>::const_iterator pBegin = deq.begin(); pBegin != deq.end(); pBegin++) {
cout << *pBegin << " ";
}
cout << endl;
}
void tetsDeque_6() {
deque<string> deq;
deq.push_back(to_string(3));
deq.push_back(to_string(9));
deq.push_back(to_string(812));
deq.push_back(to_string(5));
deq.push_front(to_string(123));
deq.push_front(to_string(785));
deq.push_front(to_string(6));
deq.push_front(to_string(7));
myPrintDeque_6(deq);
//对于支持随机访问的容器都可以使用sort()进行排序;
//数子和字符串都可以利用sort()排序,字符串按ASSCI码排序
sort(deq.begin(), deq.end());//自定义排序规则时,只用传函数名,不用加()带参数
myPrintDeque_6(deq);
}
//void main() {
// tetsDeque_6();
//}
Stack
/*stack栈
一种*先进后出**(First In Last Out,FILO)的数据结构,它只有一个出口
构造函数:
stack<T> stk;//stack采用模板类实现, stack对象的默认构造形式
stack(const stack &stk);//拷贝构造函数
赋值操作:
stack& operator=(const stack &stk);//重载等号操作符
数据存取:
void push(elem);//向栈顶添加元素
void pop();//从栈顶移除第一个元素
T top();//返回栈顶元素
大小操作:
bool empty();//判断堆栈是否为空
int size();//返回栈的大小
注意:1.队列不支持随机访问,只能访问队头和队尾元素
2.容器适配器——stack没有成员begin和end(因为栈和队列不支持迭代器,不能对任意元素进行访问);
*/
#include<iostream>
#include<stack>
using namespace std;
void testStack() {
stack<int> sta;//默认构造创建栈
//入栈
sta.push(1);
sta.push(2);
sta.push(3);
sta.push(4);
sta.push(5);
while (!sta.empty()) {//判断栈是否为空
cout << "栈的长度:" << sta.size();//栈的长度size()
cout << "\t栈顶元素为:" << sta.top();//访问栈顶元素
sta.pop();//弹出栈顶元素
cout << "\t访问并弹出后栈的长度:" << sta.size() << endl;
}
stack<int> sta1(sta);//拷贝构造
sta1 = sta;//赋值,"="号重载
}
//void main() {
// testStack();
//}
Queue
/*queue队列
一种**先进先出**(First In First Out,FIFO)的数据结构,它有两个出口
构造函数:
queue<T> que;//queue采用模板类实现,queue对象的默认构造形式
queue(const queue &que);//拷贝构造函数
赋值操作:
queue& operator=(const queue &que);//重载等号操作符
数据存取:
void push(elem);//往队尾添加元素
void pop();//从队头移除第一个元素
T back();//访问队尾元素
T front();//访问队头元素
大小操作:
bool empty();//判断堆栈是否为空
int size();//返回栈的大小
注意:1.队列不支持随机访问,只能访问队头和队尾元素
2.容器适配器——队列queue没有成员begin和end(因为栈和队列不支持迭代器,不能对任意元素进行访问);
这些插入操作会涉及到两次构造,首先是对象的初始化构造,接着在插入的时候会复制一次,会触发拷贝构造。
但是很多时候我们并不需要两次构造带来效率的浪费,如果可以在插入的时候直接构造,就只需要构造一次就够了。
C++11标准已经有这样的语法可以直接使用了,那就是emplace()
*/
#include<iostream>
#include<string>
#include<queue>
using namespace std;
void testQueue() {
queue<string> que;
//入队
que.push("唐僧");
que.push("孙悟空");
que.push("猪八戒");
que.push("沙僧");
que.push("白龙马");
que.emplace("白骨精");
while (!que.empty()) {
cout << "队列的长度:" << que.size();
cout << "\t队头的元素:" << que.front();//访问队头元素
cout << "\t队尾的元素:" << que.back();//访问队尾元素
que.pop();//出队
cout << "\t出队后队列的长度:" << que.size() << endl;//队列的长度
}
queue<string> que1(que);//拷贝构造
que1 = que;//赋值,"="号重载
}
//void main() {
// testQueue();
//}
List
/*List容器——将数据进行链式存储
链表(list)是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的
链表的组成:链表由一系列**结点**组成
结点的组成:一个是存储数据元素的**数据域**,另一个是存储下一个结点地址的**指针域**
STL中的链表是一个双向循环链表
由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于**双向迭代器**
list的优点:
1.采用动态存储分配,不会造成内存浪费和溢出
2.链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素
list的缺点:
1.链表灵活,但是空间(指针域) 和 时间(遍历)额外耗费较大
2.List有一个重要的性质,插入操作和删除操作都不会造成原有list迭代器的失效,这在vector是不成立的。
总结:STL中**List和vector是两个最常被使用的容器**,各有优缺点
构造函数:
1.list<T> lst;//默认构造
2.list(beg,end);//构造函数将[beg, end)区间中的元素拷贝给本身
3.list(n,elem);//构造函数将n个elem拷贝给本身
4.list(const list &lst);//拷贝构造
*/
#include<iostream>
#include<list>
using namespace std;
void myPrintList_1(const list<int>& L) {
for (list<int>::const_iterator pBegin = L.begin(); pBegin != L.end(); pBegin++) {//常量容器需要常量的迭代器
cout << *pBegin << " ";
}
cout << endl;
}
void testList_1() {
//1.list<T> lst;//默认构造
list<int> L1;
L1.push_back(1);
L1.push_back(2);
L1.push_back(3);
L1.push_back(4);
L1.push_back(5);
myPrintList_1(L1);
//2.list(beg,end);//构造函数将[beg, end)区间中的元素拷贝给本身
list<int> L2(L1.begin(),L1.end());
myPrintList_1(L2);
//3.list(n,elem);//构造函数将n个elem拷贝给本身
list<int> L3(10, 3);
myPrintList_1(L3);
//4.list(const list &lst);//拷贝构造
list<int> L4(L3);
myPrintList_1(L4);
//int a = L4[3];//报错,不支持随机访问(没有重写[]函数),也没有at()函数
list<int>::iterator pBegin = ++L1.begin();
cout << *pBegin << endl;
//报错,不支持随机访问(list迭代器没有重写"+"号函数),只能有pBegin++(list迭代器重写"++"函数)这种依次逐个访问
//cout << *(pBegin+1) << endl;
}
//void main() {
// testList_1();
//}
/*List 赋值和交换
函数原型:
1.assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身
2.assign(n, elem);//将n个elem拷贝赋值给本身
3.list& operator=(const list &lst);//重载等号操作符
4.swap(lst);//将lst与本身的元素互换
*/
#include<iostream>
#include<list>
using namespace std;
void myPrintList_2(const list<int>& L) {
for (list<int>::const_iterator pBegin = L.begin(); pBegin != L.end(); pBegin++) {//常量容器需要常量的迭代器
cout << *pBegin << " ";
}
cout << endl;
}
void testList_2a(){
list<int>L1;
L1.push_back(10);
L1.push_back(20);
L1.push_back(30);
L1.push_back(40);
myPrintList_2(L1);
//3.list& operator=(const list & lst);//重载等号操作符
list<int> L2;
L2 = L1;
myPrintList_2(L2);
//1.assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身
list<int> L3;
L3.assign(L2.begin(), L2.end());
myPrintList_2(L3);
//2.assign(n, elem);//将n个elem拷贝赋值给本身
list<int> L4;
L4.assign(10, 100);
myPrintList_2(L4);
}
void testList_2b(){
list<int>L1;
L1.push_back(10);
L1.push_back(20);
L1.push_back(30);
L1.push_back(40);
list<int>L2;
L2.assign(10, 100);
cout << "交换前: " << endl;
myPrintList_2(L1);
myPrintList_2(L2);
L1.swap(L2);
cout << "交换后: " << endl;
myPrintList_2(L1);
myPrintList_2(L2);
}
//void main() {
// testList_2a();
// cout<<"=====================================" << endl;
// testList_2b();
//}
/*List大小操作
函数原型:
1.size();//返回容器中元素的个数
2.empty();//判断容器是否为空
3.resize(num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删除。
4.resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删除。
*/
#include<iostream>
#include<list>
using namespace std;
void myPrintList_3(const list<int>& L) {
for (list<int>::const_iterator pBegin = L.begin(); pBegin != L.end(); pBegin++) {//常量容器需要常量的迭代器
cout << *pBegin << " ";
}
cout << endl;
}
void testList_3(){
list<int>L1;
L1.push_back(10);
L1.push_back(20);
L1.push_back(30);
L1.push_back(40);
myPrintList_3(L1);
if (L1.empty()){//2.empty();判断容器是否为空
cout << "L1为空" << endl;
}
else{
cout << "L1不为空" << endl;
cout << "L1的大小为: " << L1.size() << endl;//1.size();返回容器中元素的个数
}
L1.resize(2);//3.resize(elem);重新指定大小
myPrintList_3(L1);
L1.resize(10, 5);//4.resize(num, elem);重新指定大小
myPrintList_3(L1);
}
//void main() {
// testList_3();
//}
/*List 插入和删除
函数原型:
1.push_back(elem);//在容器尾部加入一个元素
2.pop_back();//删除容器中最后一个元素
3.push_front(elem);//在容器开头插入一个元素
4.pop_front();//从容器开头移除第一个元素
5.insert(pos,elem);//在pos位置插elem元素的拷贝,返回新数据的位置
6.insert(pos,n,elem);//在pos位置插入n个elem数据,无返回值
7.insert(pos,beg,end);//在pos位置插入[beg,end)区间的数据,无返回值
8.erase(pos);//删除pos位置的数据,返回下一个数据的位置
9.erase(beg,end);//删除[beg,end)区间的数据,返回下一个数据的位置
10.remove(elem);//删除容器中所有与elem值匹配的元素
11.clear();//移除容器的所有数据
*/
#include<iostream>
#include<list>
using namespace std;
void myPrintList_4(const list<int>& L) {
for (list<int>::const_iterator pBegin = L.begin(); pBegin != L.end(); pBegin++) {//常量容器需要常量的迭代器
cout << *pBegin << " ";
}
cout << endl;
}
void testList_4() {
list<int> L;
//1.push_back(elem);尾插
L.push_back(10);
L.push_back(20);
L.push_back(30);
//3.push_front(elem);头插
L.push_front(100);
L.push_front(200);
L.push_front(300);
myPrintList_4(L);
//2.pop_back();尾删
L.pop_back();
myPrintList_4(L);
//4.pop_front();头删
L.pop_front();
myPrintList_4(L);
//5.insert(pos,elem);//在pos位置插elem元素的拷贝,返回新数据的位置
list<int>::iterator pBegin = L.begin();
list<int>::iterator p1 = L.insert(++++pBegin, 99);//插入一个数据并返回新数据的位置
myPrintList_4(L);
//8.erase(pos);//删除pos位置的数据,返回下一个数据的位置
list<int>::iterator p2 =L.erase(p1);
myPrintList_4(L);
//6.insert(pos, n, elem);//在pos位置插入n个elem数据,无返回值
L.insert(p2, 5, 77);
myPrintList_4(L);
//7.insert(pos, beg, end);//在pos位置插入[beg,end)区间的数据,无返回值
L.insert(p2, L.begin(), ++++L.begin());
myPrintList_4(L);
//9.erase(beg, end);//删除[beg,end)区间的数据,返回下一个数据的位置
L.erase(L.begin(), ++++L.begin());
myPrintList_4(L);
//10.remove(elem);//删除容器中所有与elem值匹配的元素
L.remove(77);
myPrintList_4(L);
//11.clear();//移除容器的所有数据
L.clear();
myPrintList_4(L);
}
//void main() {
// testList_4();
//}
/*List 数据存取
函数原型:
1.front();//返回第一个元素的引用
2.back();//返回最后一个元素的引用
注意:list容器中不可以通过[]或者at方式访问数据
*/
#include<iostream>
#include<list>
using namespace std;
void myPrintList_5(const list<int>& L) {
for (list<int>::const_iterator pBegin = L.begin(); pBegin != L.end(); pBegin++) {//常量容器需要常量的迭代器
cout << *pBegin << " ";
}
cout << endl;
}
void testList_5() {
list<int>L1;
L1.push_back(10);
L1.push_back(20);
L1.push_back(30);
L1.push_back(40);
//cout << L1.at(0) << endl;//错误 不支持at访问数据
//cout << L1[0] << endl; //错误 不支持[]方式访问数据
//1.front();//返回第一个元素的引用
int& a = L1.front();
cout << "第一个元素为: " << a << endl;
a = 17;
cout << "第一个元素为: " << L1.front() << endl;//因为返回的是引用(指针),所以可以被修改
//2.back();//返回最后一个元素的引用
cout << "最后一个元素为: " << L1.back() << endl;
//list容器的迭代器是双向迭代器,不支持随机访问
list<int>::iterator pBegin = L1.begin();
//pBegin = pBegin + 1;//错误,不可以跳跃访问,即使是+1
//pBegin++;//正确,++符号函数重载了
}
//void main() {
// testList_5();
//}
/*List 反转和排序
1.reverse();//反转链表
2.sort();//链表排序,默认的排序规则从小到大
注意:sort()会根据数据量的大小采取不同的排序算法
*/
#include<iostream>
#include<list>
#include<algorithm>
using namespace std;
void myPrintList_6(const list<int>& L) {
for (list<int>::const_iterator pBegin = L.begin(); pBegin != L.end(); pBegin++) {//常量容器需要常量的迭代器
cout << *pBegin << " ";
}
cout << endl;
}
bool myCompareList_6(int a,int b) {//指定规则,从大到小
//降序:就让第一个数大于第二个数
return a>b;
}
void testList_6() {
list<int> L;
L.push_back(4);
L.push_back(3);
L.push_back(1);
L.push_back(5);
L.push_back(2);
myPrintList_6(L);
//1.reverse();//反转链表
L.reverse();
myPrintList_6(L);
//sort(L.begin(), L.end());//所有不支持随街访问迭代器的容器,都不能sort()标准算法
//不支持随街访问迭代器的容器,内部会提供一些对应的算法(成员函数)
//2.sort();//链表排序
L.sort();//默认的排序规则,从小到大
myPrintList_6(L);
L.sort(myCompareList_6);//指定规则,从大到小
myPrintList_6(L);
}
//void main() {
// testList_6();
//}
/*List 自定义数据类型的排序
通过sort()实现
案例:
将Person自定义数据类型进行排序,Person中属性有姓名、年龄、身高
排序规则:按照年龄进行拍序
实行方法:在类的里面完成"<"号和">"号的重载
*/
#include<iostream>
#include<string>
#include<list>
using namespace std;
class PersonList_7 {
public:
string myName;
int myAge;
int myHeight;
PersonList_7(string name,int age,int height) {
this->myName = name;
this->myAge = age;
this->myHeight = height;
}
bool operator<(PersonList_7 per) {//重载<号,使得list可以使用sort()默认排序
return this->myAge < per.myAge;
}
bool operator>(PersonList_7 per) {//重载<号,使得list可以使用sort()降序排序
return this->myAge > per.myAge;
}
};
void myPrintList_7(const list<PersonList_7>& L) {
for (list<PersonList_7>::const_iterator pBegin = L.begin(); pBegin != L.end(); pBegin++) {
cout << pBegin->myName << "\t" << pBegin->myAge << "\t" << pBegin->myHeight << endl;
}
}
bool myCompareList_7(PersonList_7 p1, PersonList_7 p2) {//指定规则,从大到小
//降序:就让第一个数大于第二个数
return p1 > p2;
}
void testList_7() {
PersonList_7 p1("Tom", 17, 178);
PersonList_7 p2("Mary", 18, 175);
PersonList_7 p3("Job", 25, 172);
PersonList_7 p4("Kim", 21, 168);
PersonList_7 p5("Yang", 17, 188);
list<PersonList_7> L;
L.push_back(p1);
L.push_back(p2);
L.push_back(p3);
L.push_back(p4);
L.push_back(p5);
cout << "============原始数据============" << endl;
myPrintList_7(L);
cout << "========sort默认排序后==========" << endl;
L.sort();
myPrintList_7(L);
cout << "========sort降序排序后==========" << endl;
L.sort(myCompareList_7);
myPrintList_7(L);
}
//void main() {
// testList_7();
//}
/*List 自定义数据类型的排序
通过sort()实现
案例:
将Person自定义数据类型进行排序,Person中属性有姓名、年龄、身高
排序规则:按照年龄进行降序,年龄相同时按身高升序
实现方法:在类外实现(注意于List_7.cpp(类内实现)对比)
这种方法可以实现任何想要的排序方式
*/
#include<iostream>
#include<string>
#include<list>
using namespace std;
class PersonList_8 {
public:
string myName;
int myAge;
int myHeight;
PersonList_8(string name, int age, int height) {
this->myName = name;
this->myAge = age;
this->myHeight = height;
}
};
void myPrintList_8(const list<PersonList_8>& L) {
for (list<PersonList_8>::const_iterator pBegin = L.begin(); pBegin != L.end(); pBegin++) {
cout << pBegin->myName << "\t" << pBegin->myAge << "\t" << pBegin->myHeight << endl;
}
}
bool myCompareList_8(PersonList_8 p1, PersonList_8 p2) {//指定规则,这种方法可以实现任何想要的排序方式
if (p1.myAge == p2.myAge) {
return p1.myHeight < p2.myHeight;//年龄相等时,按身高升序(第一个数据小于第二个数据)
}
else {
return p1.myAge > p2.myAge;//先按年龄降序(第一个数据大于第二个数据)
}
}
void testList_8() {
PersonList_8 p1("Tom", 17, 178);
PersonList_8 p2("Mary", 18, 175);
PersonList_8 p3("Job", 25, 172);
PersonList_8 p4("Kim", 21, 168);
PersonList_8 p5("Yang", 17, 188);
PersonList_8 p6("Tian", 17, 168);
PersonList_8 p7("Mei", 17, 175);
PersonList_8 p8("Zhen", 17, 171);
list<PersonList_8> L;
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);
cout << "============原始数据============" << endl;
myPrintList_8(L);
//默认排序会报错,因为没有重写"<"号,无法对比两个自定义数据类型的大小
/*cout << "========sort默认排序后==========" << endl;
L.sort();
myPrintList_8(L);*/
cout << "===========sort排序后===========" << endl;
L.sort(myCompareList_8);//自定义的数据类型一定要自己指定排序规则,只用传函数名,不用加()带参数
myPrintList_8(L);
}
//void main() {
// testList_8();
//}
Set
/*Pair数据成对的出现
构造函数:
1.pair<type, type> p (value1, value2);
2.pair<type, type> p = make_pair(value1, value2);
嵌套使用:
1.pair<type, pair<type,type>> p(value1, {value2, value3});
*/
#include<iostream>
#include<string>
using namespace std;
void testPair_1() {
//1.pair<type, type> p(value1, value2);
pair<string, int> p1("唐僧", 25);
cout << "姓名:" << p1.first << "\t年龄:" << p1.second << endl;
//2.pair<type, type> p = make_pair(value1, value2);
pair<string, int> p2 = make_pair("孙悟空", 999);
cout << "姓名:" << p2.first << "\t年龄:" << p2.second << endl;
//嵌套使用
//1.pair<type, pair<type,type>> p(value1, {value2, value3});
pair<string, pair<int, int>>p3("猪八戒", { 765, 765 });
cout << "姓名:" << p3.first << "\t年龄:" << p3.second.first << "\t年龄:" << p3.second.second << endl;
}
//void main() {
// testPair_1();
//}
/*Set容器——所有元素都会在插入时自动被排序
本质——set/multiset属于**关联式容器**,底层结构是用**二叉树**实现
set和multiset区别:
set不允许容器中有重复的元素
multiset允许容器中有重复的元素
构造函数:
1.set<T> st;//默认构造函数:
2.set(const set &st);//拷贝构造函数
赋值:
set& operator=(const set &st);//重载等号操作符
*/
#include<iostream>
#include<set>
using namespace std;
void myPrintSet_1(const set<int>& s) {
for (set<int>::const_iterator pBegin = s.begin(); pBegin != s.end(); pBegin++) {
cout << *pBegin << " ";
}
cout << endl;
}
void myPrintMultiset_1(const multiset<int>& s) {
for (multiset<int>::const_iterator pBegin = s.begin(); pBegin != s.end(); pBegin++) {
cout << *pBegin << " ";
}
cout << endl;
}
void testSet_1() {
//1.set<T> st;//默认构造函数:
set<int> s1;
//插入数据 只有insert()方式
s1.insert(4);
s1.insert(2);
s1.insert(3);
s1.insert(5);
s1.insert(1);
myPrintSet_1(s1);//所有元素都会在插入时自动被排序
cout << "set容器的长度:" << s1.size() << endl;
s1.insert(1);
s1.insert(1);
s1.insert(1);
myPrintSet_1(s1);//set不允许容器中有重复的元素,但插入的时候不会报错,无效插入
cout << "set容器的长度:" << s1.size() << endl;
//2.set(const set & st);//拷贝构造函数
set<int> s2(s1);
multiset<int> s3;
s3.insert(3);
s3.insert(2);
s3.insert(1);
s3.insert(1);
s3.insert(2);
myPrintMultiset_1(s3);//multiset允许容器中有重复的元素
cout << "multiset容器的长度:" << s1.size() << endl;
}
//void main() {
// testSet_1();
//}
/*Set容器的大小和交换
函数原型:
1.size();//返回容器中元素的数目
2.empty();//判断容器是否为空
3.swap(st);//交换两个集合容器
*/
#include<iostream>
#include<set>
using namespace std;
void myPrintSet_2(const set<int>& s) {
for (set<int>::const_iterator pBegin = s.begin(); pBegin != s.end(); pBegin++) {
cout << *pBegin << " ";
}
cout << endl;
}
void testSet_2a() {
set<int> s1;
s1.insert(10);
s1.insert(30);
s1.insert(20);
s1.insert(40);
if (s1.empty()){
cout << "s1为空" << endl; //2.empty();//判断容器是否为空
}
else{
cout << "s1不为空" << endl;
cout << "s1的大小为: " << s1.size() << endl;//1.size();//返回容器中元素的数目
}
}
void testSet_2b() {
set<int> s1;
s1.insert(10);
s1.insert(30);
s1.insert(20);
s1.insert(40);
set<int> s2;
s2.insert(100);
s2.insert(300);
s2.insert(200);
s2.insert(400);
cout << "交换前" << endl;
myPrintSet_2(s1);
myPrintSet_2(s2);
cout << endl;
cout << "交换后" << endl;
s1.swap(s2);
myPrintSet_2(s1);
myPrintSet_2(s2);
}
//void main() {
// testSet_2a();
// cout << "================================" << endl;
// testSet_2b();
//}
/*Set容器的插入和删除
函数原型:
1.insert(elem);//在容器中插入元素
2.erase(pos);//删除pos迭代器所指的元素,返回下一个元素的迭代器
3.erase(beg, end);//删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器
4.erase(elem);//删除容器中值为elem的元素
5.clear();//清除所有元素
注意:set不支持随机访问,不支持[],at(),"+"
*/
#include<iostream>
#include<set>
using namespace std;
void myPrintSet_3(const set<int>& s) {
for (set<int>::const_iterator pBegin = s.begin(); pBegin != s.end(); pBegin++) {
cout << *pBegin << " ";
}
cout << endl;
}
void testSet_3() {
set<int> s1;
//1.insert(elem);//在容器中插入元素
s1.insert(10);
s1.insert(30);
s1.insert(20);
s1.insert(40);
myPrintSet_3(s1);
//2.erase(pos);//删除pos迭代器所指的元素,返回下一个元素的迭代器
s1.erase(s1.begin());
myPrintSet_3(s1);
//3.erase(beg, end);//删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器
s1.erase(s1.begin(), ++s1.begin());//不支持随机访问
//4.erase(elem);//删除容器中值为elem的元素
s1.erase(30);
myPrintSet_3(s1);
//5.clear();//清除所有元素
s1.clear();
//s1.erase(s1.begin(), s1.end());//这种方式也可以清空
myPrintSet_3(s1);
}
//void main() {
// testSet_3();
//}
/*Set查找和统计
对set容器进行查找数据以及统计数据
函数原型:
1.find(key);//查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();
2.count(key);//统计key的元素个数
注意:
查找--- find (返回的是迭代器)
统计--- count (对于set,结果为0或者1)
*/
#include<iostream>
#include<set>
using namespace std;
void testSet_4() {
set<int> s1;
//插入
s1.insert(10);
s1.insert(30);
s1.insert(20);
s1.insert(40);
//1.find(key);//查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();
set<int>::iterator pos = s1.find(30);
if (pos != s1.end()){
cout << "找到了元素 : " << *pos << endl;
}
else{
cout << "未找到元素" << endl;
}
//2.count(key);//统计key的元素个数
int num = s1.count(30);
cout << "num = " << num << endl;
}
//void main() {
// testSet_4();
//}
/*set和multiset区别
区别:
1.set不可以插入重复数据,而multiset可以
2.set插入数据的同时会返回两个东西,插入位置的迭代器和插入是否成功(bool型),成对返回pair
3.multiset不会检测数据,因此可以插入重复数据,插入时只返回迭代器(指向插入数据的位置)
*/
#include<iostream>
#include<set>
using namespace std;
void myPrintSet_5(const set<int>& s) {
for (set<int>::const_iterator pBegin = s.begin(); pBegin != s.end(); pBegin++) {
cout << *pBegin << " ";
}
cout << endl;
}
void myPrintMultiset_5(const multiset<int>& s) {
for (multiset<int>::const_iterator pBegin = s.begin(); pBegin != s.end(); pBegin++) {
cout << *pBegin << " ";
}
cout << endl;
}
void testSet_5a() {
set<int> s;
pair<set<int>::iterator, bool> ret1 = s.insert(10);//第一次插入10
pair<set<int>::iterator, bool> ret2 = s.insert(10);//第二次插入10
if (ret1.second) {
cout << "第一次插入10插入成功" << endl;
cout << "*ret1.first=" << *ret1.first << endl;//虽然ret1.first是记录数据插入的位置迭代器
}
else {
cout << "第一次插入10插入失败" << endl;
}
if (ret2.second) {
cout << "第二次插入10插入成功" << endl;
}
else {
cout << "第二次插入10插入失败" << endl;
cout << "*ret2.first=" << *ret2.first << endl;//虽然*ret2.first仍然记录了的数据,但实质并没有插入
}
}
void testSet_5b() {
multiset<int> ms;
//multiset可以插入重复值
multiset<int>::iterator ret1 = ms.insert(10);//第一次插入10
multiset<int>::iterator ret2 = ms.insert(10);//第二次插入10
myPrintMultiset_5(ms);
cout << "*ret1=" << *ret1 << endl;
cout << "*ret2=" << *ret2 << endl;
if (ret1 == ret2) {
cout << "ret1等于ret2" << endl;
}
else {
cout << "ret1不等于ret2" << endl;
}
}
//void main() {
// testSet_5a();
// cout << "================================" << endl;
// testSet_5b();
//}
/*set容器排序
**示例一** set存放内置数据类型
set容器默认排序规则为从小到大,掌握如何改变排序规则
利用仿函数,可以改变排序规则
*/
#include<iostream>
#include<set>
using namespace std;
class myCompareSet_6 {//利用仿函数从新制定排序规则
public:
bool operator()(int v1, int v2) const {//vs2019要在后面加const,常函数
//降序,第一个数大于第二个数
return v1 > v2;
}
};
void testSet_6() {
set<int> s1;
s1.insert(10);
s1.insert(60);
s1.insert(20);
s1.insert(40);
s1.insert(50);
s1.insert(30);
//默认从小到大
for (set<int>::const_iterator pBegin = s1.begin(); pBegin != s1.end(); pBegin++) {
cout << *pBegin << " ";
}
cout << endl;
set<int,myCompareSet_6> s2;
s2.insert(10);
s2.insert(60);
s2.insert(20);
s2.insert(40);
s2.insert(50);
s2.insert(30);
for (set<int, myCompareSet_6>::const_iterator pBegin = s2.begin(); pBegin != s2.end(); pBegin++) {
cout << *pBegin << " ";
}
cout << endl;
}
//void main() {
// testSet_6();
//}
/*set容器排序
**示例二** set存放自定义数据类型
注意:
1.set容器默认排序规则为从小到大,掌握如何改变排序规则
2.利用仿函数,可以改变排序规则
3.对于自定义数据类型,set必须指定排序规则才可以插入数据
*/
#include<iostream>
#include<set>
#include<string>
using namespace std;
class PersonSet_7 {
public:
string myName;
int myAge;
PersonSet_7(string name,int age) {
this->myName = name;
this->myAge = age;
}
};
class myCompareSet_7 {//利用仿函数从新制定排序规则
public:
//vs2019要在后面加const,常函数
bool operator()(const PersonSet_7 &p1, const PersonSet_7 &p2) const {
//降序,第一个数大于第二个数
return p1.myAge > p2.myAge;
}
};
void testSet_7() {
set<PersonSet_7, myCompareSet_7> s;
PersonSet_7 p1("唐僧", 25);
PersonSet_7 p2("孙悟空", 999);
PersonSet_7 p3("猪八戒", 758);
PersonSet_7 p4("沙僧", 625);
PersonSet_7 p5("白龙马", 422);
//对自定义的数据类型都要先指定排序方式,才能插入
s.insert(p1);
s.insert(p2);
s.insert(p3);
s.insert(p4);
s.insert(p5);
for (set<PersonSet_7, myCompareSet_7>::const_iterator pBegin = s.begin(); pBegin != s.end(); pBegin++) {
cout << pBegin->myName << "\t" << pBegin->myAge << endl;
}
}
//void main() {
// testSet_7();
//}
Map
/*Map容器(用的多)——python字典
map中所有元素都是pair:
pair中第一个元素为key(键值),起到索引作用,第二个元素为value(实值)
所有元素都会根据元素的键值自动排序
本质:
map/multimap属于**关联式容器**,底层结构是用二叉树实现
优点:
可以根据key值快速找到value值
map和multimap区别:
map不允许容器中有重复key值元素
multimap允许容器中有重复key值元素
构造函数:
1.map<T1, T2> mp;//map默认构造函数:
2.map(const map &mp);//拷贝构造函数
赋值:
map& operator=(const map &mp);//重载等号操作符
总结:map中所有元素都是成对出现,插入数据时候要使用对组
map在插入元素时,默认按键值排序
*/
#include<iostream>
#include<map>
#include<string>
using namespace std;
void myPrintMap_1(map<int,string>& m) {
for (map<int, string>::iterator pBegin = m.begin(); pBegin != m.end(); pBegin++) {
cout << "key:" << pBegin->first << "\t" << pBegin->second << endl;
}
}
void testMap_1() {
//1.map<T1, T2> mp;//map默认构造函数:
map<int, string> m1;
m1.insert(pair<int, string>(105, "唐僧"));
m1.insert(pair<int, string>(102, "孙悟空"));
m1.insert(pair<int, string>(101, "猪八戒"));
m1.insert(pair<int, string>(104, "沙僧"));
m1.insert(pair<int, string>(103, "白龙马"));
myPrintMap_1(m1);
cout<< "=========================" << endl;
//2.map(const map &mp);//拷贝构造函数
map<int, string> m2(m1);
myPrintMap_1(m2);
cout << "=========================" << endl;
//赋值:map& operator=(const map & mp);//重载等号操作符
map<int, string> m3;
m3 = m2;
myPrintMap_1(m3);
}
//void main() {
// testMap_1();
//}
/*Map大小和交换
函数原型:
1.size();//返回容器中元素的数目
2.empty();//判断容器是否为空
3.swap(st);//交换两个集合容器
*/
#include<iostream>
#include<map>
#include<string>
using namespace std;
void myPrintMap_2(map<int, int>& m) {
for (map<int, int>::iterator pBegin = m.begin(); pBegin != m.end(); pBegin++) {
cout << "key:" << pBegin->first << "\t" << pBegin->second << endl;
}
}
void testMap_2a() {
map<int, int>m;
m.insert(pair<int, int>(1, 10));
m.insert(pair<int, int>(2, 20));
m.insert(pair<int, int>(3, 30));
if (m.empty()){//2.empty();//判断容器是否为空
cout << "m为空" << endl;
}
else{
cout << "m不为空" << endl;//1.size();//返回容器中元素的数目
cout << "m的大小为: " << m.size() << endl;
}
}
void testMap_2b() {
map<int, int>m1;
m1.insert(pair<int, int>(1, 10));
m1.insert(pair<int, int>(2, 20));
m1.insert(pair<int, int>(3, 30));
map<int, int>m2;
m2.insert(pair<int, int>(4, 100));
m2.insert(pair<int, int>(5, 200));
m2.insert(pair<int, int>(6, 300));
cout << "交换前" << endl;
myPrintMap_2(m1);
myPrintMap_2(m2);
cout << "交换后" << endl;
m1.swap(m2);//3.swap(st);//交换两个集合容器
myPrintMap_2(m1);
myPrintMap_2(m2);
}
//void main() {
// testMap_2a();
// cout << "=========================" << endl;
// testMap_2b();
//}
/*Map插入和删除
函数原型:
1.insert(elem);//在容器中插入元素
map[key] = value;//也可插入元素,不建议
2.erase(pos);//删除pos迭代器所指的元素,返回下一个元素的迭代器
3.erase(beg, end);//删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器
4.erase(key);//删除容器中值为key的元素
5.clear();//清除所有元素
*/
#include<iostream>
#include<map>
#include<string>
using namespace std;
void myPrintMap_3(map<int, string>& m) {
for (map<int, string>::iterator pBegin = m.begin(); pBegin != m.end(); pBegin++) {
cout << "key:" << pBegin->first << "\t" << pBegin->second << endl;
}
}
void testMap_3() {
map<int, string> m;
//1.insert(elem);//在容器中插入元素
//insert()有四种方式插入,主要是对的写的方式不同
// 推荐第1,2种
//第一种方式插入
m.insert(pair<int, string>(1, "唐僧"));
//第二种方式插入
m.insert(make_pair(2, "孙悟空"));
//第三种方式插入
m.insert(map<int, string>::value_type(3, "猪八戒"));
//第四种方式插入
m[4] = "沙僧";//不建议使用[]的方式插入,例如map中已有key=4的数据,会覆盖原来的数据
myPrintMap_3(m);
cout << "=========================" << endl;
//第二次插入同键值的数据
//四种插入方式只有第四种会覆盖原来的值,其他的都插入不进去(不报错)
//[]用来访问数据,最好不要用来插入数据
//[]用来访问没有该键值的元素时,会插入该键值
m.insert(pair<int, string>(1, "丫丫"));
m.insert(make_pair(2, "丫丫"));
m.insert(map<int, string>::value_type(3, "丫丫"));
m[4] = "丫丫";
cout << m[10] << endl;//访问key=10(没有该键值),插入默认value为空
myPrintMap_3(m);
cout << "=========================" << endl;
//2.erase(pos);//删除pos迭代器所指的元素,返回下一个元素的迭代器
m.erase(m.begin());
myPrintMap_3(m);
cout << "=========================" << endl;
//3.erase(beg, end);//删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器
m.erase(m.begin(), ++m.begin());
myPrintMap_3(m);
cout << "=========================" << endl;
//4.erase(key);//删除容器中值为key的元素
m.erase(4);
myPrintMap_3(m);
cout << "=========================" << endl;
//5.clear();//清除所有元素
m.clear();
myPrintMap_3(m);
}
//void main() {
// testMap_3();
//}
/*Map查找和统计
*
函数原型:
find(key);//查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回map.end();
count(key);//统计key的元素个数
注意:
- 查找 --- find (返回的是迭代器)
- 统计 --- count(对于map,结果为0或者1)
*/
#include<iostream>
#include<map>
using namespace std;
void testMap_4() {
map<int, int>m;
m.insert(pair<int, int>(1, 10));
m.insert(pair<int, int>(2, 20));
m.insert(pair<int, int>(3, 30));
//查找
map<int, int>::iterator pos = m.find(3);
if (pos != m.end()){
cout << "找到了元素 key = " << pos->first << " value = " << pos->second << endl;
}
else{
cout << "未找到元素" << endl;
}
//统计
int num = m.count(3);
cout << "num = " << num << endl;
}
//void main() {
// testMap_4();
//}
/*Map容器排序
- map容器默认排序规则为 按照key值进行 从小到大排序,掌握如何改变排序规则
- 利用仿函数,可以改变排序规则
- 对于自定义数据类型,map必须要指定排序规则,同set容器
*/
#include<iostream>
#include<map>
#include<string>
using namespace std;
class myCompareMap_5 {
public:
bool operator()(int v1,int v2) const{//map里面是按键值排序,所以比较的是键值的数据类型
return v1 > v2;
}
};
void testMap_5() {
map<int, string> m1;//默认排序,按键值的升序,只用传仿函数名,不用加()
m1[3] = "Tom";
m1[1] = "Yang";
m1[2] = "Mary";
m1[5] = "Job";
m1[4] = "Ken";
for (map<int, string>::iterator pBegin = m1.begin(); pBegin != m1.end(); pBegin++) {
cout << "key:" << pBegin->first << "\t" << pBegin->second << endl;
}
cout << "=========================" << endl;
map<int, string, myCompareMap_5> m2;//自定义,降序排列,只用传仿函数名,不用加()
m2[3] = "Tom";
m2[1] = "Yang";
m2[2] = "Mary";
m2[5] = "Job";
m2[4] = "Ken";
for (map<int, string, myCompareMap_5>::iterator pBegin = m2.begin(); pBegin != m2.end(); pBegin++) {
cout << "key:" << pBegin->first << "\t" << pBegin->second << endl;
}
}
//void main() {
// testMap_5();
//}
String
/*string容器
本质:string是C++风格的字符串,而string本质上是一个类
string和char区别:
1.char是一个指针
2.string是一个类,类内部封装了char*,管理这个字符串,是一个char*型的容器。
特点:
1.string 类内部封装了很多成员方法
查找find,拷贝copy,删除delete 替换replace,插入insert
2.string管理char*所分配的内存,不用担心复制越界和取值越界等,由类内部进行负责
string构造函数:
1.string(); //默认构造,创建一个空的字符串 例如: string str;
2.string(const char* s); //使用字符串常量初始化
3.string(const string& str); //拷贝构造,使用一个string对象初始化另一个string对象
4.string(int n, char c); //使用n个字符c初始化
*/
#include<iostream>
#include<string>
using namespace std;
void testStr_1() {
string str1;//1.默认构造
string str2("hello");//2.使用字符串s初始化
cout << "str2: " << str2 << endl;
string str3(str2);//3.拷贝构造
cout << "str3: " << str3 << endl;
string str4(10, 'a');//4.
cout << "str4: " << str4 << endl;
}
//void main() {
// testStr_1();
//}
/*string赋值操作
*赋值方法:
1.str1 = "hello"; //char*类型字符串,赋值给当前的字符串
2.str2 = str1; //把字符串s赋给当前的字符串
3.str3 = 'a'; //字符赋值给当前的字符串
4.str4.assign("hello C++"); //把字符串s赋给当前的字符串
5.str5.assign("hello C++",n); //把字符串s的前n个字符赋给当前的字符串
6.str6.assign(str4); //把字符串s赋给当前字符串
7.str7.assign(n, 'a'); //用n个字符c赋给当前字符串
*/
#include<iostream>
#include<string>
using namespace std;
void testStr_2() {
string str1;
str1 = "hello";//1.字符串常量赋值给当前字符串
cout << "str1=" << str1 << endl;
string str2;
str2 = str1;//2.把一个字符串的值赋值给另一个字符串
cout << "str2=" << str2 << endl;
string str3;
str3 = 'a';//3.给字符串赋值一个字符
cout << "str3=" << str3 << endl;
string str4;
str4.assign("hello C++");//4.利用assign()函数,把字符串常量赋值给当前字符串
cout << "str4=" << str4 << endl;
string str5;
str5.assign("hello C++",5);//5.利用assign()函数,把字符串常量的前n个字符赋值给当前字符串
cout << "str5=" << str5 << endl;
string str6;
str6.assign(str4);//6.利用assign()函数,把一个字符串的值赋值给另一个字符串
cout << "str6=" << str6 << endl;
string str7;
str7.assign(10, 'a');//7.利用assign()函数,给字符串赋值n个连续的字符
cout << "str7=" << str7 << endl;
}
//void main() {
// testStr_2();
//}
/*字符串拼接
1.string& operator+=(const char* str); //重载+=操作符
2.string& operator+=(const char c); //重载+=操作符
3.string& operator+=(const string& str); //重载+=操作符
4.string& append(const char *s); //把字符串常量s连接到当前字符串结尾
5.string& append(const char *s, int n); //把字符串常量s的前n个字符连接到当前字符串结尾
6.string& append(const char *s, int pos, int n); //把字符串常量s从下标pos开始到结尾的字符连接到字符串结尾
7.string& append(const string &s); //同operator+=(const string& str)
8.string& append(const string &s, int pos); //字符串s中从下标pos开始到结尾的字符连接到字符串结尾
9.string& append(const string &s, int pos, int n); //字符串s中从下标pos开始的n个字符连接到字符串结尾
*/
#include<iostream>
#include<string>
using namespace std;
void testStr_3() {
string str1 = "好好学习";
string str2 = "天天向上";
str1 += "哦";//1.重载+=操作符,追加字符串常量
cout << "str1=" << str1 << endl;
str1 = "好好学习";
str2 = "天天向上";
str1 += 'o';//2.重载+=操作符,追加字符常量
cout << "str1=" << str1 << endl;
str1 = "好好学习";
str2 = "天天向上";
str1 += str2;//3.重载+=操作符,追加字符串
cout << "str1=" << str1 << endl;
str1 = "好好学习";
str2 = "天天向上";
string str = str1.append("哦哦");//4.使用append()函数将字符串常量加到该字符串的尾部
cout << "str=" << str << endl;
str1 = "好好学习";
str2 = "12345678";
str = str1.append("12345678", 3);//5.使用append()函数将字符串常量前n个字符加到该字符串的尾部
cout << "str=" << str << endl;
str1 = "好好学习";
str2 = "12345678";
str = str1.append("12345678", 2, 3);//6.使用append()函数将字符串常量从下标为n1开始的n2个字符加到该字符串的尾部
cout << "str=" << str << endl;
str1 = "好好学习";
str2 = "12345678";
str = str1.append(str2);//7.使用append()函数将一个字符串加到另一个字符串的尾部
cout << "str=" << str << endl;
str1 = "好好学习";
str2 = "12345678";
str = str1.append(str2,2);//8.使用append()函数将一个字符串从下标为n到末尾的字符加到另一个字符串的尾部
cout << "str=" << str << endl;
str1 = "好好学习";
str2 = "12345678";
str = str1.append(str2, 2, 4);//9.使用append()函数将一个字符串从下标为n1开始的n2个字符加到该字符串的尾部
cout << "str=" << str << endl;
}
//void main() {
// testStr_3();
//}
/*字符串的查找和替换
* 查找:查找指定字符串是否存在
* 替换:在指定的位置替换字符串
==============================================================================================
* 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个字符为字符串str
* string& replace(int pos, int n,const char* s); //替换从pos开始的n个字符为字符串s
*/
#include<iostream>
#include<string>
using namespace std;
void testStr_4a() {
string str1 = "abcdefgde";
//1.利用find()函数从左至右查找第一个出现的地方
int pos1 = str1.find("de");//利用find()函数查找,找到返回下标,没找到返回-1
int pos2 = str1.find("df");//利用find()函数查找,找到返回下标,没找到返回-1
cout << "de的下标" << pos1 << endl;
cout << "df的下标" << pos2 << endl;
//2.利用rfind()函数从右至左查找第一个出现的地方
int pos3 = str1.rfind("de");
int pos4 = str1.rfind("df");
cout << "de的下标" << pos3 << endl;
cout << "df的下标" << pos4 << endl;
}
void testStr_4b() {
string str2 = "abcdefg";
//利用replace()函数将字符串从pos下标开始n个字符替换为新串
str2 = str2.replace(1, 3, "12345");
cout << "str2=" << str2 << endl;
}
//void main() {
// testStr_4a();
// testStr_4b();
//}
/*
字符串的比较:字符串比较是按字符的ASCII码进行对比
两字符串相等 = 返回 0
ASCII大 > 返回 1
ASCII小 < 返回 -1
语法:
int compare(const string &s) const; //与字符串s比较
int compare(const char *s) const; //与字符串s比较
*/
#include<iostream>
#include<string>
using namespace std;
void testStr_5() {
string str1 = "hello";
string str2 = "xello";
string str3 = {'h','e','l','l','o'};
char str4[] = "hello";//不是字符串,不能调用字符串的函数
char str5[] = { 'h','e','l','l','o' };//不是字符串,不能调用字符串的函数
cout << "str1.size():" << str1.size() << endl;
cout << "sizeof(str1):" << sizeof(str1) << endl;
cout << "sizeof(str2):" << sizeof(str2) << endl;
cout << "sizeof(str3):" << sizeof(str3) << endl;
cout << "sizeof(str4):" << sizeof(str4) << endl;
cout << "sizeof(str5):" << sizeof(str5) << endl;
//利用compare()比较两个字符串,相等返回0
cout << "str1.compare(str2):" << str1.compare(str2) << endl;
cout << "str1.compare(str3):" << str1.compare(str3) << endl;
}
//void main() {
// testStr_5();
//}
/*
string的单个字符读和写(修改)
1.通过[]访问单个字符
2.通过at(int i)函数方式访问单个字符
*/
#include<iostream>
#include<string>
using namespace std;
void testStr_6() {
string str = "hello";
//读
//1.通过[]访问单个字符
for (int i = 0; i < str.size(); i++) {
cout << str[i] << " ";
}
cout << endl;
//2.通过at(int i)函数方式访问单个字符
for (int i = 0; i < str.size(); i++) {
cout << str.at(i) << " ";
}
cout << endl;
//写(修改)
//1.通过[]修改单个字符
str[0] = 'e';
//2.通过at(int i)函数方式修改单个字符
str.at(1) = 'x';
cout << "str:" << str << endl;
}
//void main() {
// testStr_6();
//}
/*
string插入和删除
1.string& insert(int pos, const char* s); //插入字符串
2.string& insert(int pos, const string& str); //插入字符串
3.string& insert(int pos, int n, char c); //在指定位置插入n个字符c
4.string& erase(int pos, int n = npos); //删除从Pos开始的n个字符
*/
#include<iostream>
#include<string>
using namespace std;
void testStr_7() {
string str = "hello";
cout << "str:" << str << endl;
str.insert(1, "123");//2.插入字符串
cout << "str:" << str << endl;
str = "hello";
str.insert(1, 3, '5');//3.插入n个字符
cout << "str:" << str << endl;
str.erase(1, 3);//4.删除从Pos开始的n个字符
cout << "str:" << str << endl;
}
//void main() {
// testStr_7();
//}
/*
string求子串
string substr(int pos = 0, int n = npos) const; //返回由pos开始的n个字符组成的字符串
*/
#include<iostream>
#include<string>
using namespace std;
void testStr_8() {
string str = "0123456789";
string substr = str.substr(1, 5);
cout << "substr:" << substr << endl;
//实用操作--重邮箱中截取用户名
string email_1 = "jkouyang@163.com";
string email_2 = "ouyjk@mail2.sysu.edu.cn";
int flag1 = email_1.find('@');
int flag2 = email_2.find('@');
string username_1 = email_1.substr(0, flag1);
string username_2 = email_2.substr(0, flag2);
cout << "username_1:" << username_1 << endl;
cout << "username_2:" << username_2 << endl;
}
//void main() {
// testStr_8();
//}
/*string 大小
*
int size();
int length();
bool empty();
void resize(n);
int capacity();
void reserve();
int max_size()
* 注意:
length是沿用C语言而保留下来的,引入STL之后,为了兼容又加入了size(兼容STL接口),其实两者一样
string类的size()/length()方法返回的是字节数,不管是否有汉字。
*/
#include<iostream>
#include<string>
using namespace std;
void testStr_9() {
string str = "123abc\0abc";
cout << "str:" << str << endl;
cout << "str.size():" << str.size() << endl;//size(),length()两者一样
cout << "str.length():" << str.length() << endl;
cout << "sizeof(str):" << sizeof(str) << endl;//string所占的字节
cout << "str.capacity():" << str.capacity() << endl;//兼容STL,引入capacity()
bool flag = str.empty();
str.resize(3);
cout << "str:" << str << endl;
str.resize(13,'a');//超过的默认填充'/0'
cout << "str:" << str << endl;
}
//void main() {
// testStr_9();
//}