string容器
构造
#include <string>
//string构造
void test01()
{
string s1; //创建空字符串,调用无参构造函数
cout << "str1 = " << s1 << endl;
const char* str = "hello world";
string s2(str); //把c_string转换成了string
cout << "str2 = " << s2 << endl;
string s3(s2); //调用拷贝构造函数
cout << "str3 = " << s3 << endl;
string s4(10, 'a');//输出10个a
cout << "str3 = " << s3 << endl;
}
赋值操作
void test01()
{
//直接赋值
str1 = "hello world";
string str2;
//用另一个字符串赋值
str2 = str1;
//单个字符赋值
str3 = 'a';
//使用assign赋值
str4.assign("hello c++");
str5.assign("hello c++",5);
str6.assign(str5);
str7.assign(5, 'x');
}
总结:string的赋值方式很多,operator= 这种方式是比较实用的
字符串拼接操作
str3.append(" love ");
str3.append("game abcde", 4);//前四个字符
str3.append(str2, 4, 3); // 从下标4位置开始 ,截取3个字符,拼接到字符串末尾
str1 += "爱玩游戏";
str1 += str2;
字符串查找和替换
//查找
string str1 = "abcdefgde";
int pos = str1.find("de");//找的到的话返回首字母下标 找不到返回-1
pos = str1.rfind("de");//refind是从右往左找 这个案例返回7
//替换
string str1 = "abcdefgde";
//从1号位置起三个字符 替换为"1111"
str1.replace(1, 3, "1111");
string字符串比较
/*字符串对比主要是用于比较两个字符串是否相等,判断谁大谁小的意义并不是很大
*/
string str1 = "hello";
string str2 = "hello";
str1.compare(str2);//返回0
string字符存取
//string 字符存取
string str1;
str1.size();//返回字符串的长度
//访问单个字符
str1[i];
str1.at(i);
//修改单个字符
str1[0] = 'x';
str.at(1)='x';
string插入删除
//字符串插入和删除
string str1 = "hello";
//插入
str1.insert(1,"111");//插入后变成了 h111ello
//删除
str1.erase(1,3);//从第一个位置起删多少个 hello
string字串
//截取字串
string str = "abcdef";
string subStr = str.substr(1,3);//从第一个开始截3个
//使用操作
string email1 = "ceaserk01@163.com";
//从邮件中获取用户名信息
int pos = email.find("@");
string usrName = eamil.substr(0,pos);
vector容器
基本概念
vector和数组非常相似,也称为单端数组
和普通数组区别是:数组是静态空间,而vector可以动态扩展
vector容器是支持随机访问的迭代器
构造
vector<T> v; //采用模板实现类实现,默认构造函数
vector(v.begin(), v.end()); //将v[begin(), end())区间中的元素拷贝给本身。
vector(n, elem); //构造函数将n个elem拷贝给本身。
vector(const vector &vec); //拷贝构造函数。
vector<int> v1; //无参构造
//通过区间的方式进行构造
vector<int> v2(v1.begin(), v1.end());
//构造函数将n个elem拷贝给本身
vector<int> v3(10, 100);
//拷贝构造
vector<int> v4(v3);
赋值操作
vector<int> v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
// 等号赋值
vector <int> v2;
v2=v1;
// assign
vector <int> v3;
v3.assign(v1.begin(),v1.end());
//n个elem方式赋值
vector<int> v4;
v4.assign(10,100);
大小操作
/*
empty(); //判断容器是否为空
capacity(); //容器的容量
size(); //返回容器中元素的个数
resize(int num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删除。
resize(int num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删除
*/
v1.empty(); //返回true或false 为真代表容器为空
resize(int num); //如果重新指定的比原来长了,默认用0填充新的位置
插入和删除
vector<int> v1;
//尾插法
v1.push_back(10);
v2.push_back(20);
//尾删法
v1.pop_back();//删除最后一个元素
//插入
v1.insert(v1.begin(),100);//第一个参数是迭代器
v1.insert(v1.begin(),2,1000);//在指定的位置上插入n个数据
//删除
v1.erase(v1.begin());//参数也是迭代器 删除第一个1000
//清空容器
v1.erase(v1.begin(),v1.end());
v1.clear();
数据存取
//vector容器的数据存取
vector<int> v1;
//利用中括号的方式来访问数组中的元素
v1[i]
//利用at方式访问元素
v1.at(i)
//获取第一个元素
v1.front();
//获取最后一个元素
v1.back();
互换容器
//容器互换基本使用
vector<int> v1; //0 1 2 3 4 5 6 7 8 9
vector<int> v2; //10 9 8 7 6 5 4 3 2 1
//交换后
v1.swap(v2);
v1// 10 9 8 7 6 5 4 3 2 1
v2// 0 1 2 3 4 5 6 7 8 9
//实际用途
//巧用swap可以收缩空间
vector<int> v3;
//假设现在v3的capacity是10000 但size是3 可以用swap来收缩空间
vector<int>(v3).swap(v3);
//vector<int>(v3) 匿名对象 .swap(v)容器交换
预留空间
//利用reserve预留空间 不用在vector扩展空间的时候反复开辟新空间
vector<int> v;
v.reserve(10000);
deque容器
基本概念
功能:
双端数组,可以对头端进行插入删除操作
deque与vector区别:
vector对于头部的插入删除效率低,数据量越大,效率越低
deque相对而言,对头部的插入删除速度回比vector快
vector访问元素时的速度会比deque快,这和两者内部实现有关
![](https://i-blog.csdnimg.cn/blog_migrate/628126058b7bdaaed5d06d294fdc5efb.jpeg)
deque内部工作原理:
deque内部有个中控器,维护每段缓冲区中的内容,缓冲区中存放真实数据
中控器维护的是每个缓冲区的地址,使得使用deque时像一片连续的内存空间
deque容器的迭代器也是支持随机访问的
![](https://i-blog.csdnimg.cn/blog_migrate/3cbdda000128d332a6d33e447e69d319.jpeg)
构造
deque<T> deqT //默认构造形式
deque(beg, end); //构造函数将[beg, end)区间中的元素拷贝给本身。
deque(n, elem); //构造函数将n个elem拷贝给本身。
deque(const deque &deq); //拷贝构造函数
deque<int> d1; //无参构造函数
//通过区间的方式进行构造
d2(d1.begin(),d1.end());
//构造函数将n个elem拷贝给本身。
deque<int>d3(10,100);
//拷贝构造函数
deque<int>d4(d3);
赋值操作
// 等号赋值
deque<int> d1;
deque<int> d2;
d2 = d1;
//assign 赋值
deque<int> d3;
d3.assign(d1.begin(),d1.end());
//将n个elem拷贝赋值给本身
deque<int> d4;
d4.assign(10,100);
大小操作
deque<int> d1;
d1.empty();//返回true或false 为真代表容器为空
d1.size();//返回容器中元素的个数
d1.resize(num);//重新指定容器的长度为num,若容器变长,则以默认值填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删除。
d1.resize(15, 1);//重新指定容器的长度为num,若容器变长,则以1填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删除。
注意:deque没有容量概念
插入和删除
两端插入操作:
push_back(elem); //在容器尾部添加一个数据
push_front(elem); //在容器头部插入一个数据
pop_back(); //删除容器最后一个数据
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位置的数据,返回下一个数据的位置。
//两端进行插入操作
deque<int> d;
//尾插
d.push_back(10);
d.push_back(20);
//头插
d.push_front(100);
d.push_front(200);
//尾删
d.pop_back();
//头删
d.pop_front();
printDeque(d);
//使用insert方法进行插入
deque<int> d1;// 1 2 3 4
d1.insert(d1.begin(),1000);//1000 1 2 3 4
d1.insert(d1.begin(),2,10000);//10000 10000 1000 1 2 3 4
//按照区间的方式进行插入
deque<int> d2;// 1 2 3
d1.insert(d1.begin(),d2.begin(),d2.end());
//1 2 3 10000 10000 1000 1 2 3 4
//删除
deque<int>::iterator it = d1.begin();
it++;
d1.erase(it);
//按区间方式删除
d1.erase(d1.begin(),d2.begin());
//清空
d1.clear();
数据存取
deque <int> d1;// 1 2 3 4
//通过中括号访问
d1[i];
//通过at访问
d1.at(i);
//front back
d.front();
d.back();
排序-sort
deque<int> d1;
sort(d1.begin(),d1.end());//对d1中所有的数据进行从小到大排序
注意:sort 默认从小到大升序
对于支持随机访问的迭代器的容器,都可以用sort直接对其进行排序.
比如 vector
栈 stack容器
基本概念
栈是一种后进先出的数据结构,LIFO.
栈不允许有遍历行为
栈可以判断是否为空吗? 可以 empty
栈可以返回元素的个数吗? 可以 size
常用接口
构造函数:
stack<T> stk; //stack采用模板类实现, stack对象的默认构造形式
stack(const stack &stk); //拷贝构造函数
赋值操作:
stack& operator=(const stack &stk); //重载等号操作符
数据存取:
push(elem); //向栈顶添加元素
pop(); //从栈顶移除第一个元素
top(); //返回栈顶元素
大小操作:
empty(); //判断堆栈是否为空
size(); //返回栈的大小
#include <stack>
//栈容器常用接口
void test01()
{
//创建栈容器 栈容器必须符合先进后出
stack<int> s;
//向栈中添加元素,叫做 压栈 入栈
s.push(10);
s.push(20);
s.push(30);
while (!s.empty()) {
//输出栈顶元素
cout << "栈顶元素为: " << s.top() << endl;
//弹出栈顶元素
s.pop();
}
cout << "栈的大小为:" << s.size() << endl;
}
int main() {
test01();
system("pause");
return 0;
}
list容器
构造函数
//创建list容器
list<int>L1; //默认构造
//区间方式构造
list<int>L2(L1.begin(), L1.end());
//拷贝构造
list<int>L3(L2);
//n个elem
list<int>L4(10, 1000);
赋值和交换
//赋值
list<int>L1;
list<int>L2;
L2 = L1; // operator= 赋值
//assign赋值
list<int>L3;
L3.assign(L2.begin(), L2.end());//将[beg, end)区间中的数据拷贝赋值给本身。
list<int>L4;
L4.assign(10, 100);将n个elem拷贝赋值给本身。
//交换
list<int>L1;//10 20 30 40
list<int>L2;
L2.assign(10, 100);
L1.swap(L2);//交换
大小操作
//list容器大小操作
list<int>L1;
//判断容器是否为空
L1.empty();//空返回true
//重新指定大小
L1.resize(10, 10000);
L1.resize(2);
resize(num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删除。
resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删除。
插入和删除
//list容器插入和删除
/*
- push_back(elem);//在容器尾部加入一个元素
- pop_back();//删除容器中最后一个元素
- push_front(elem);//在容器开头插入一个元素
- pop_front();//从容器开头移除第一个元素
- insert(pos,elem);//在pos位置插elem元素的拷贝,返回新数据的位置。
- insert(pos,n,elem);//在pos位置插入n个elem数据,无返回值。
- insert(pos,beg,end);//在pos位置插入[beg,end)区间的数据,无返回值。
- clear();//移除容器的所有数据
- erase(beg,end);//删除[beg,end)区间的数据,返回下一个数据的位置。
- erase(pos);//删除pos位置的数据,返回下一个数据的位置。
- remove(elem);//删除容器中所有与elem值匹配的元素。
*/
list<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);
// 300 200 100 10 20 30
printList(L);
//尾删
L.pop_back();
// 300 200 100 10 20
printList(L);
//头删
L.pop_front();
// 200 100 10 20
printList(L);
//insert插入
list<int>::iterator it = L.begin();
L.insert(++it, 1000);
// 200 1000 100 10 20
printList(L);
//删除
it = L.begin();
L.erase(++it);
// 200 100 10 20
printList(L);
//移除
L.push_back(10000);
L.push_back(10000);
L.push_back(10000);
L.push_back(10000);
printList(L);
L.remove(10000);
printList(L);
//清空
L.clear();
printList(L);
数据存取
>
//list容器 数据存取
list<int>L1;
L1.push_back(10);
L1.push_back(20);
L1.push_back(30);
L1.push_back(40);
//L1[0] 不可以用[]访问list容器中的元素
//L1.at(0) 不可以用at方式访问list容器中的元素
//原因是list本质链表,不是用连续线性空间存储数据,迭代器也是不支持随机访问的
cout << "第一个元素为:" << L1.front() << endl;
cout << "最后一个元素为: " << L1.back() << endl;
//验证迭代器是不支持随机访问的
//it = it + 1 //出错
list<int>::iterator it = L1.begin();
it++; //支持双向
it--;
//it = it + 1; //不支持随机访问
反转和排序
//list容器反转和排序
//反转
list<int>L1;
L1.reverse();
bool myCompare(int v1 ,int v2)
{
//降序 就让第一个数 > 第二个数
return v1 > v2;
}
//排序
list<int>L1;
//所有不支持随机访问迭代器的容器,不可以用标准算法
//不支持随机访问迭代器的容器,内部会提供对应一些算法
//sort(L1.begin(), L1.end());
L1.sort(); //默认排序规则 从小到大 升序
L1.sort(myCompare);
排序案例
#include<iostream>
using namespace std;
#include <string>
#include <list>
//list容器 排序案例 对于自定义数据类型 做排序
//按照年龄进行升序,如果年龄相同按照身高进行降序
class Person
{
public:
Person(string name,int age,int height)
{
this->m_Name = name;
this->m_Age = age;
this->m_Height = height;
}
string m_Name; //姓名
int m_Age; //年龄
int m_Height; // 身高
};
//指定排序规则
bool comparePerson(Person &p1,Person &p2)
{
//按照年龄 升序
if (p1.m_Age == p2.m_Age)
{
//年龄相同 按照身高降序
return p1.m_Height > p2.m_Height;
}
else
{
return p1.m_Age < p2.m_Age;
}
}
void test01()
{
list<Person>L; //创建容器
//准备数据
Person p1("刘备", 35, 175);
Person p2("曹操", 45, 180);
Person p3("孙权", 40, 170);
Person p4("赵云", 25, 190);
Person p5("张飞", 35, 160);
Person p6("关羽", 35, 200);
//插入数据
L.push_back(p1);
L.push_back(p2);
L.push_back(p3);
L.push_back(p4);
L.push_back(p5);
L.push_back(p6);
for (list<Person>::iterator it = L.begin(); it != L.end(); it++)
{
cout << "姓名: " << (*it).m_Name << " 年龄: " << it->m_Age << " 身高: " << it->m_Height << endl;
}
//排序
cout << "---------------------------------" << endl;
cout << "排序后:" << endl;
L.sort(comparePerson);
for (list<Person>::iterator it = L.begin(); it != L.end(); it++)
{
cout << "姓名: " << (*it).m_Name << " 年龄: " << it->m_Age << " 身高: " << it->m_Height << endl;
}
}
int main() {
test01();
system("pause");
return 0;
}
对于自定义数据类型,必须要指定排序规则,否则编译器都不知道如何进行排序
set容器
基本概念
简介:
所有元素都会在插入时自动被排序
本质:
set/multiset属于关联式容器,底层结构是用二叉树实现。
set和multiset区别:
set不允许容器中有重复的元素
multiset允许容器中有重复的元素
set构造和赋值
功能描述:创建set容器以及赋值
构造:
set<T> st; //默认构造函数:
set(const set &st); //拷贝构造函数
赋值:
set& operator=(const set &st); //重载等号操作符
#include<iostream>
using namespace std;
#include <set>
//set容器构造和赋值
void printSet(set<int>&s)
{
for (set<int>::iterator it = s.begin(); it != s.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
set<int>s1;
//插入数据 只有insert方式
s1.insert(10);
s1.insert(40);
s1.insert(30);
s1.insert(20);
s1.insert(30);
//遍历容器
//set容器特点:所有元素插入时候自动被排序
//set容器不允许插入重复值,插了但不会报错,但是插不成功的
printSet(s1);
//拷贝构造
set<int>s2(s1);
//赋值
set<int>s3;
s3 = s2;
printSet(s3);
}
set大小和交换
功能描述:
统计set容器大小以及交换set容器
函数原型:
size(); //返回容器中元素的数目
empty(); //判断容器是否为空
swap(st); //交换两个集合容器
//set容器 大小和交换
//大小
set<int>s1;
//判断是否为空
s1.empty();
s1.size();
//交换
set<int>s1;
set<int>s2;
s1.swap(s2);
set插入和删除
功能描述:
set容器进行插入数据和删除数据
函数原型:
insert(elem); //在容器中插入元素。
clear(); //清除所有元素
erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器。
erase(beg, end); //删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
erase(elem); //删除容器中值为elem的元素。
//set容器 插入和删除
set<int>s1;
//插入
s1.insert(30);
s1.insert(10);
s1.insert(20);
s1.insert(40);
//删除
s1.erase(s1.begin());
printSet(s1);//20 30 40
//删除重载版本
s1.erase(30);
printSet(s1);//20 40
//清空
//s1.erase(s1.begin(), s1.end());
s1.clear();
set查找和统计
功能描述:
对set容器进行查找数据以及统计数据
函数原型:
find(key); //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();
count(key); //统计key的元素个数 对于set而言 结果为0或者1
set<int>::iterator pos = s1.find(30);
if (pos != s1.end())
{
cout << "找到元素:" << *pos << endl;
}
else
{
cout << "未找到元素" << endl;
}
//查找
set<int>s1;
//插入数据
s1.insert(10);
s1.insert(30);
s1.insert(20);
s1.insert(40);
//统计30的个数
int num = s1.count(30);
//对于set而言 统计结果 要么是0 要么是1
set和multset区别
区别:
set不可以插入重复数据,而multiset可以
set插入数据的同时会返回插入结果,表示插入是否成功
multiset不会检测数据,因此可以插入重复数据
pair对组创建
功能描述:
成对出现的数据,利用对组可以返回两个数据
两种创建方式:
pair<type, type> p ( value1, value2 );
pair<type, type> p = make_pair( value1, value2 );
两种方式都可以创建对组,记住一种即可
pair<string, int> p(string("Tom"), 20);
cout << "姓名: " << p.first << " 年龄: " << p.second << endl;
pair<string, int> p2 = make_pair("Jerry", 10);
cout << "姓名: " << p2.first << " 年龄: " << p2.second << endl;
set排序
set容器需要在插入数据之前就规定排序规则
set<int, MyCompare>s2;
class MyCompare
{
public:
//第一个小括号代表重载的符号 第二个小括号代表重载括号函数体的参数列表
bool operator()(int v1,int v2)
{
return v1 > v2;
}
};
set自定义数据类型排序
#include <set>
#include <string>
class Person
{
public:
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
}
string m_Name;
int m_Age;
};
class comparePerson
{
public:
bool operator()(const Person& p1, const Person &p2)
{
//按照年龄进行排序 降序
return p1.m_Age > p2.m_Age;
}
};
void test01()
{
set<Person, comparePerson> s;
Person p1("刘备", 23);
Person p2("关羽", 27);
Person p3("张飞", 25);
Person p4("赵云", 21);
s.insert(p1);
s.insert(p2);
s.insert(p3);
s.insert(p4);
for (set<Person, comparePerson>::iterator it = s.begin(); it != s.end(); it++)
{
cout << "姓名: " << it->m_Name << " 年龄: " << it->m_Age << endl;
}
}
int main() {
test01();
system("pause");
return 0;
}
map容器
map中所有元素都是pair
pair中第一个元素为key(键值),起到索引作用,第二个元素为value(实值)
所有元素都会根据元素的键值自动排序
本质:
map/multimap属于关联式容器,底层结构是用二叉树实现。
优点:
可以根据key值快速找到value值
map和multimap区别:
map不允许容器中有重复key值元素
multimap允许容器中有重复key值元素
构造和赋值
//map容器 构造和赋值
void printMap(map<int, int>&m)
{
for (map<int, int>::iterator it = m.begin(); it != m.end(); it++)
{
cout << "key = " << (*it).first << " value = " << it->second << endl;
}
cout << endl;
}
void test01()
{
//创建map容器
map<int, int> m;
//插入数据
m.insert(pair<int, int>(1, 10));
m.insert(pair<int, int>(3, 30));
m.insert(pair<int, int>(2, 20));
m.insert(pair<int, int>(4, 40));
printMap(m);
//拷贝构造
map<int, int>m2(m);
printMap(m2);
//赋值
map<int, int>m3;
m3 = m2;
printMap(m3);
}
大小与交换
//大小操作
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));
m.empty();
m.size();
//交换
map<int, int>m;
map<int, int>m2;
m.swap(m2);
插入和删除
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;
//[]不建议插入,用途 可以利用key访问到value
//cout << m[4] << endl;
//删除
m.erase(m.begin());
printMap(m);//20 30 40
m.erase(3); //按照key删除
printMap(m);
//清空
//m.erase(m.begin(), m.end());
m.clear();
查找和统计
find(key); //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();
count(key); //统计key的元素个数
//查找
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));
m.insert(pair<int, int>(3, 40));
map<int,int>::iterator pos = m.find(3);
if (pos != m.end())
{
cout << "查到了元素 key = " << (*pos).first << " value = " << pos->second << endl;
}
else
{
cout << "未找到元素" << endl;
}
//统计
//map不允许插入重复key 元素 ,count统计而言 结果要么是0 要么是1
//multimap的count统计可能大于1
int num = m.count(3);
cout << "num = " << num << endl;
学习目标:
map容器默认排序规则为 按照key值进行 从小到大排序,掌握如何改变排序规则
主要技术点:
利用仿函数,可以改变排序规则
class MyCompare {
public:
bool operator()(int v1, int v2) {
return v1 > v2;
}
};
void test01()
{
//默认从小到大排序
//利用仿函数实现从大到小排序
map<int, int, MyCompare> m;
m.insert(make_pair(1, 10));
m.insert(make_pair(2, 20));
m.insert(make_pair(3, 30));
m.insert(make_pair(4, 40));
m.insert(make_pair(5, 50));
for (map<int, int, MyCompare>::iterator it = m.begin(); it != m.end(); it++) {
cout << "key:" << it->first << " value:" << it->second << endl;
}
}
示例:
总结:
利用仿函数可以指定map容器的排序规则
对于自定义数据类型,map必须要指定排序规则,同set容器