vector
1、构造
vector<int> v(5, 5); // 开辟5个空间,每个位置都填充5
vector<int> v1(v.begin(), v.end()); // 将v的前闭后开区间的值 构造v1
vector<int> v3(v.begin(), v.begin() + 2); // 前闭后开
vector<int> v2(v); // 拷贝构造
2、赋值操作
vector<int> v1(5, 5);
vector<int> v2;
v2= v1; // v1赋值给v2
vector<int> v3;
v3.assign(v1.begin(), v1.end()); // 区间赋值,前闭后开
vector<int> v4;
v4.assign(10, 100); // 将10个100赋值给v4
3、大小操作
vector<int> v(4, 5);
v.push_back(10);
int count = v.size(); // 返回容器中元素的个数
cout << count << endl;
count = v.capacity(); // 返回容器的大小
cout << count << endl;
bool flag = v.empty(); // 判断容器是否为空,空返回true,否则false
// 重新指定大小
v.resize(10); // 10个大小空间,若容器中不够10个默认用0填充
v.resize(10, 100); // 用100填充
v.push_back(11); // 尾插到重定义大小之后
cout << endl;
v.resize(4); // 如果指定大小比原来变小了,超出部分被删除掉
4、遍历
方式1:通过迭代器访问
template <typename T>
void printVector(vector<T>& sp)
{
auto f = sp.begin();// 起始迭代器,指向第一个元素
auto l = sp.end();// 结束迭代器,指向最后一个元素的下一个
while(f != l) {
cout << *f << " ";
++f;
}
cout << endl;
}
或者使用for循环
for (vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
cout << *it << endl;
}
方式2:利用STL提供的for_each
void myPrint(int val)
{
cout << val << endl;
}
template <typename T>
void printVector(vector<T>& v)
{
for_each(v.begin(), v.end(), myPrint); // 传入遍历的区间和操作
}
5、插入和删除操作
vector<int> v(5, 5);
v.push_back(2); // 尾插
v.pop_back(); //尾删
// 插入
v.insert(v.begin(), 2);// 迭代器处插入,此时为头插
v.insert(v.begin()+2, 3, 100); // 在2索引处插入3个100
// 删除
v.erase(v.begin()); // 删除迭代器指向的元素
v.erase(v.begin(), v.begin()+2); // 删除0-2索引,前闭后开
v.clear(); // 清空
6、数据存取
vector<int> v(5, 5);
int temp = v.back(); // 返回容器中最后一个元素
cout << temp << endl;
temp = v.front(); // 返回第一个元素
cout << temp << endl;
temp = v.at(2); // 访问 下标为2处的元素
cout << temp << endl;
temp = v[2]; // // 访问 下标为2处的元素
cout << temp << endl;
v[2] = 22; // 修改指定下标处元素
v.at(3) = 33; // 修改指定下标处元素
7、互换操作
vector<int> v(5, 5);
vector<int> v1(1, 4);
v.swap(v1); // v与v1互换
v1.swap(v); // 这两种调用方式没有区别
printVector(v);
printVector(v1);
swap的用途:内存收缩
vector<int> v;
for (int i = 0; i < 100000; ++i) {
v.push_back(i);
}
cout << "V的容量:" << v.capacity() << endl;
cout << "V的大小:" << v.size() << endl;
// 这时V的容量已经很大了,但是后续我们并不需要这么多的空间
v.resize(10); // 比如现在只需要10个空间,那么后续的几万空间都是多余的。
cout << "V的容量:" << v.capacity() << endl; // 还是之前的容器所以容量还是那么大
cout << "V的大小:" << v.size() << endl;
// 重指定大小不会缩小之前已经扩充的容器容量,只是改变了size
// 这时就可以用swap进行内存收缩
vector<int>(v).swap(v); // 创建一个匿名对象与v做交换
cout << "V的容量:" << v.capacity() << endl; // 变为指定的10
cout << "V的大小:" << v.size() << endl;
8、预留空间
// 减少vector在动态扩容时的扩展次数
vector<int> v;
int count = 0;
int capa = v.capacity();
v.reserve(100000);
// 如果预留100000,那么1次就开辟100000
for (int i = 0; i < 100000; ++i) {
v.push_back(i);
if (capa != v.capacity()) {
capa = v.capacity();
++count;
}
// 看一下扩容了多少次
}
cout << "扩容了:" << count << "次" << endl; // 30次 加了reserve后扩容一次
cout << "V的容量:" << v.capacity() << endl;
cout << "V的大小:" << v.size() << endl;
string
1、构造
// 构造函数
string str1; // 默认构造
string str2("123"); //初始化构造
string str3(str1); // 拷贝构造
string str4(3, 'a'); // 使用n个字符a初始化构造 "aaa"
2、赋值操作
string str1;
str1 = "hello world!";
string str2;
str2 = str1; // = 重载不是拷贝构造
string str3;
str3 = 'a'; // 将字符 转换为字符串 赋给str3
string str4;
str4.assign("hello C++"); // 函数的形式赋值,
string str5;
str5.assign("hello C++", 3); // 将“hello C++” 的前3个付给str5
string str6;
str6.assign(5, 'a'); // 5个a的字符串给str6 "aaaaa"
string str7;
str7.assign(str5); // str5赋值给str7
// 实际上底层 对"="赋值运算符的重载用的也是assign成员函数。一般用“=”
3、拼接操作
string str1 = "我";
str1 += "C++"; // 打印“我C++”
str1 += '.'; //也可以拼接字符 打印“我C++.”
string str2 = "LOL DNF CF";
str1 += str2; // 也可以追加string类似的字符串
string str3 = "I";
str3.append(" love"); // 成员函数拼接 “I love”
str3.append(" 12345", 3); // 将字符串的前3个拼接给str3 “I love 12”
str3.append(str1); // "I love 12 我"
str3.append("abcdef", 1, 3); // 从下标1开始截取3个 <==> str3+=“bcd”
str3.append(str2, 2, 3); // 从下标2开始截取3个,若截取个数超过了字符串的长度,那么到结尾停止截取
str3.append(str2, 8); // 从下标8开始到结尾
// 底层重载+=运算符实际上都是用的append成员函数。
4、字符串的查找和替换
// 查找
string str1 = "LOL DNF CF DN";
int pos = str1.find("DN"); // 查询指定字符串的首个下标 返回4
cout << pos << endl;
pos = str1.find("Dn"); // 查找不到返回-1 返回-1
cout << pos << endl;
pos = str1.rfind("DN"); // 倒着查,返回11
cout << pos << endl;
// 替换
str1.replace(1, 3, "1234"); // 从1索引开始的3个字符长度替换为"1234"
cout << str1 << endl;
5、字符串的比较
string str1 = "123";
string str2 = "123";
int flag = str1.compare(str2); // 相等返回0,不相等返回ASCCI码差
cout << flag << endl;
bool ff = str1 == str2; // 相等返回1,不相等返回0
cout << ff << endl;
6、字符串的字符存取
[] 的重载 at()成员函数
string str1 = "hello";
cout << str1[0] << endl; // 打印 h
cout << str1.at(1) << endl; // 打印 e
// 修改单个字符
str1[2] = 'f';
cout << str1 << endl; // 打印“heflo”
str1.at(3) = 'f';
cout << str1 << endl; // 打印“heffo”
7、插入和删除
string str1 = "hello";
str1.insert(1, "111");
cout << str1 << endl; // 在1索引插入“111” 打印“h111elo”
str1.erase(1, 3); // 从1索引位置删除3个字符 打印“hello”
cout << str1 << endl;
8、子串截取
string str = "hello";
string str1 = str.substr(1, 3); // 从1索引截取3个字符返回子串
cout << str1 << endl;
str1 = str.substr(3, 5); // 如果越界,则遇到字符串结尾停止
cout << str1 << endl;
stack 栈
1、构造与赋值
stack<int> s; // 默认构造
stack<int> s1(s); // 拷贝构造
stack<int> s2;
s2 = s1; // 赋值操作
2、栈的接口
栈不允许有遍历操作
stack<int> s; // 默认构造
s.push(10); // 入栈
s.push(12);
s.push(14);
s.pop(); // 出栈
stack<int> s1(s); // 拷贝构造
int size = s1.size(); // 返回栈中元素个数
int top = s1.top(); // 返回栈顶元素
bool flag = s1.empty(); // 判断栈是否为空,空返回true,反之false
set与multiset
set 与 multiset的区别:
1、set是存取无序且元素不可重复的。底层是红黑树实现,插入时会自动排序且去重
2、multiset是可以有重复元素的
1、构造与赋值
set<int> st;// 默认构造
set<int> st1(st); // 拷贝构造
set<int> st2;
st2 = st1; // 赋值
2、遍历
template <typename T>
void printSet(set<T>& sp)
{
for (auto it = sp.begin(); it != sp.end(); ++it) {
cout << *it << " ";
}
cout << endl;
}
template <typename T>
void printMultiset(multiset<T>& sp)
{
for (auto it = sp.begin(); it != sp.end(); ++it) {
cout << *it << " ";
}
cout << endl;
}
3、set与multiset区别展示
set<int> st;
st.insert(1);
st.insert(3);
st.insert(2);
st.insert(4);
st.insert(4);
printSet(st); // 打印1 2 3 4 自动排序去重
multiset<int> st1;
st1.insert(1);
st1.insert(3);
st1.insert(4);
st1.insert(4);
st1.insert(2);
printMultiset(st1); // 打印 1 2 3 4 4 自动排序但不去重
4、大小和交换操作
set是不支持resize重新指定大小的
set<int> st;
st.insert(1);
st.insert(3);
st.insert(2);
st.insert(4);
int size = st.size(); // 返回容器中元素的个数
bool flag = st.empty(); // 判空
set<int> st1;
st.swap(st1); // 交换
5、插入和删除
set<int> st;
st.insert(1); // 插入一个元素
set<int>::iterator it = st.begin(); // 不支持随机访问
++it;
it = st.erase(it); // 删除迭代器指向的元素,返回下一个元素的迭代器
st.erase(2); // 按值删除
st.erase(it, ++it); // 区间删除前闭后开
st.clear(); // 清空
6、查询和统计
set<int> st;
set<int>::iterator it = st.find(2); // 查找元素2,找到返回迭代器位置,找不到返回end
int count = st.count(2);
// 统计指定元素个数,对于set只有0和1,对于multiset可能大于1
7、排序规则
class MyCompare
{
public:
bool operator()(int v1, int v2) const // 通过仿函数实现新的排序规则
{
return v1 > v2;
}
};
// 改变排序规则
void demo()
{
set<int> st1;
st1.insert(1);
st1.insert(3);
st1.insert(2);
st1.insert(4);
printSet(st1); // 默认升序
set<int, MyCompare> st2; // 通过对自定义MyCompare类“()”的重载 实现自定义排序规则
st2.insert(1);
st2.insert(3);
st2.insert(2);
st2.insert(4);
for (set<int, MyCompare>::iterator it = st2.begin(); it != st2.end(); ++it) {
cout << *it << " ";
}
cout << endl; // 打印 4 3 2 1
}
自定义类型排序
// 存放自定义类型时必须指定仿函数,确定排序规则
class Person
{
public:
Person(string name, int age){
this->name = name;
this->age = age;
}
string name;
int age;
};
class compare
{
public:
bool operator()(const Person& p1, const Person& p2) const {
return p1.age > p2.age;
}
};
void demo()
{
set<Person, compare> s1;
s1.insert(Person("vv", 12));
s1.insert(Person("aa", 16));
s1.insert(Person("bb", 13));
s1.insert(Person("cc", 11));
for (set<Person, compare>::iterator it = s1.begin(); it != s1.end(); ++it) {
cout << it->name << it->age << endl;
} // 按年龄降序
}
queue队列
队列不允许有遍历的行为
1、构造及其接口
queue<int> q; // 默认构造
q.push(10); // 队尾插入 入队
q.push(12);
queue<int> q1(q); // 拷贝构造
queue<int> q2;
q2 = q1; // 赋值操作
q1.pop(); // 队头删除 出队
int f = q1.front(); // 返回队头元素
int b = q1.back(); // 返回队尾元素
int size = q1.size(); // 返回队中元素个数
bool flag = q1.empty();// 判断队列是否为空
pair对组
1、对组的创建与使用
pair<int, int> p(1, 12); // 键值对 (key, value)键值对的类型可以自定义
pair<int, string> p2 = make_pair(1, "12"); // 这两种方式效果一样
// 获取
cout << p.first << " : " << p.second << endl;
cout << p2.first << " : " << p2.second << endl;
map
- map中所有元素都是pair对组
- 对组的第一个是键第二个是值,通过pair.first pair.second 获取
- 所有元素在插入时会通过键值自动排序
- 本质:map/multimap 都属于关联式容器,底层使用二叉树实现
- 优点:可以根据key值快速找到value值
- map与multimap的区别:map中不允许有重复的键key,multimap中可以有重复的键key
1、遍历
template <typename K,typename V>
void printMap(map<K, V>& m)
{
for (auto it = m.begin(); it != m.end(); ++it) {
cout << it->first << " : " << it->second << endl;
}
}
2、大小与交换操作
map<int, int> mm;
int size = mm.size(); // 返回map容器中的键值对的个数
bool flag = mm.empty(); // 判空
map<int, int> m2;
m2.swap(mm); // 交换
3、插入和删除
map<int, int> mm;
mm.insert(pair<int, int>(1,10));
mm.insert(pair<int, int>(2,20));
mm.insert(pair<int, int>(3,30)); // 第一种
mm.insert(make_pair(4, 40));
mm.insert(make_pair(5, 50)); // 第二种
mm.insert(map<int, int>::value_type(6, 60)); // 第三种
mm[7] = 70; // 第四种 若通过[]访问的键不存在,map会自动创建一个键值对值为0
// 插入时前两种最为常用,通过键访问值时一般用[]的方式
mm[3] = 20; // 键=3的键值对已存在,将30修改为20
printMap(mm);
map<int, int>::iterator it = mm.begin();
it = mm.erase(it, ++it); // 区间删除,前闭后开 返回下一个元素的迭代器
it = mm.erase(it); // 删除迭代器指向的元素,返回下一个元素的迭代器
bool flag = mm.erase(0); // 按键值 删除,通过键删除这条键值对 成功返回1,失败返回0
mm.clear(); // 清空
4、查找和统计
map<int, int> mm;
mm.insert(make_pair(4, 40));
mm.insert(make_pair(5, 50));
map<int, int>::iterator it = mm.find(3); // 成功返回键=3的pair对组,失败返回end
// 统计
int num = mm.count(3); // 统计键=3的键值对的个数,对于map来说只有0和1
multimap<int, int> m2;
m2.insert(make_pair(4, 40));
m2.insert(make_pair(4, 40));
m2.insert(make_pair(4, 40));
m2.insert(make_pair(5, 50));
num = m2.count(4); // multimap可能大于1
cout << num << endl;
5、map的排序
类似于set
class MyCompare
{
public:
bool operator()(int v1, int v2) const {
return v1 > v2;
}
};
// map的排序
void demo()
{
map<int, int, MyCompare> m1;
m1.insert(make_pair(1, 10));
m1.insert(make_pair(2, 20));
m1.insert(make_pair(5, 50));
m1.insert(make_pair(3, 30));
m1.insert(make_pair(4, 40));
for (auto it = m1.begin(); it != m1.end(); ++it) {
cout << it->first << ":" << it->second << endl;
}
}
list链表
1、遍历
void printList(list<int>& sp)
{
for (list<int>::iterator it = sp.begin(); it != sp.end(); ++it) {
cout << *it << " ";
}
cout << endl;
}
2、构造
list<int> l1; // 默认构造
list<int> L1(2); // 开辟2个大小空间值默认为0
list<int> l2(l1); // 拷贝构造
list<int> l3(l1.begin(), l1.end()); // 区间构造
list<int> l4(4, 5); // 指定初始值 4 个 5 构造
3、赋值和交换操作
list<int> L1(4, 5);
list<int> L2;
L2 = L1;
list<int> L3;
L3.assign(L1.begin(), L1.end()); // 区间赋值
L3.assign(6, 6); // 6 个 6赋值给L3
L1.swap(L3);
L3.swap(L1); // 这两种写法效果上没有区别,都是交换两个容器
4、大小操作
list<int> L1(4, 5);
int size = L1.size(); // 返回容器中的元素个数
bool flag = L1.empty(); // 判空
L1.resize(6); // 重新指定容器的大小,若边长默认用0填充
L1.resize(3); // 若变短,删除超出的
L1.resize(6, 4); // 超出部分用指定的元素填充,若变短 同上
5、插入和删除
list<int> L1(4, 5);
list<int> L2(5, 3);
L1.push_back(6); // 尾插
L1.pop_back(); // 尾删
L1.push_front(7); // 头插
L1.pop_front(); // 头删
list<int>::iterator it = L1.begin(); // list 迭代器不支持随机访问,只能双向迭代
L1.insert(++it, 3); // 中间插入,在迭代器指定处插入元素3
L1.insert(it, L2.begin(), L2.end()); // 在迭代器指定处 区间插入前闭后开
L1.insert(it, 3, 8); // 在迭代器指定处 插入 3个8
it = L2.begin();
L2.erase(++it); // 删除迭代器指向的元素
L2.erase(++it, L2.end()); // 区间删除 前闭后开
L2.remove(3); // 按值删除,删除容器中所有3
L2.clear(); // 清空
6、存取操作
list<int> L1(2);
L1.push_back(2);
L1.push_back(3);
L1.push_back(4);
L1.push_back(5);
L1.push_back(6);
int f_val = L1.front(); // 返回第一个元素
int l_val = L1.back(); // 返回最后一个元素
7、反转和排序
注意:所有不支持随机访问迭代器的容器不能使用标准算法。
但是 对于这种不支持随机访问迭代器的容器,内部都对相关算法进行了封装
bool myCompaper(int a, int b)
{
return a > b;
}
// 反转和排序
void demo()
{
list<int> L1(1,1);
L1.push_back(2);
L1.push_back(3);
L1.push_back(4);
L1.push_back(5);
L1.push_back(6);
printList(L1);
L1.reverse(); // 逆序
printList(L1);
// 排序
// sort(L1.begin(), L1.end()); //不支持
L1.sort(); // 默认升序
printList(L1);
L1.sort(myCompaper); // 也可以自定义比较方式,入参为函数地址
printList(L1);
}
deque
- deque 内部工作原理:
- deque内部有个中控器,维护每个缓冲区的内容,缓冲区中存放真实数据
- 中控器维护的是每个缓冲区的首地址,使得使用deque时像是在使用连续的内存空间
- 头尾增删快,访问慢
1、遍历
template <typename T>
void printDeque(const deque<T> & sp)
{
// 只读迭代
for (auto it = sp.begin(); it != sp.end(); ++it) {
cout << *it << " ";
}
cout << endl;
}
2、构造
deque<int> d1;
for (int i = 0; i < 10; ++i) {
d1.push_back(i);
}
printDeque(d1);
deque<int> d2(d1.begin(), d1.begin() + 3); // 区间赋值构造
printDeque(d2);
deque<int> d3(10, 100); // 10个100
printDeque(d3);
deque<int> d4(d3); // 拷贝构造
printDeque(d4);
3、赋值操作
deque<int> d1(5, 5);
deque<int> d2;
d2 = d1; // d1 赋值给d2
d2.assign(d1.begin(), d1.begin()+2); // 前闭后开
d2.assign(4, 2);// 4个2赋值给d2
4、大小操作
deque<int> d1(5, 5);
bool flag = d1.empty(); // 判空
int size = d1.size(); // 只有大小,没有容量,deque容量是无限扩充的
d1.resize(10); // 大小重定义默认0填充
d1.resize(10, 2); // 2填充
d1.resize(3); // 如果重定义比原来的小,则删除超出的
5、插入和删除
deque<int> d1(5, 5);
d1.push_back(3); // 尾插
d1.push_front(3); // 头插
d1.pop_back(); // 尾删
d1.pop_front(); // 头删
// 中间插入删除操作
d1.insert(d1.begin()+2, 1000); // 在下标2处插入1000
d1.insert(d1.begin() + 2, 2, 100); // 在下标2处插入2个100
deque<int> d2(4, 1);
//在d2的1索引位置插入d1的[1,4)区间的值
d2.insert(d2.begin()+1, d1.begin() + 1, d1.begin() + 4);
d2.erase(d2.begin()+1); // 删除下标1处的元素
d2.erase(d2.begin(), d2.begin()+3); // 区间删除,前闭后开
d2.clear(); // 清空
6、数据存取
deque<int> d1(5, 5);
int temp = d1[0];
temp = d1.at(2); // 访问指定下标处的元素
d1[0] = 10;
d1.at(2) = 10; // 修改指定下标处的元素
temp = d1.front(); // 返回容器中第一个元素
temp = d1.back(); // 返回容器最后一个元素