声明:其中所有内容是自己在学习过程中所作的笔记,部分内容是来源于网络资源和c++ primer,也是自己辛苦一字一字打出来的,其它内容在之后进行补充。(使用的是obsidian编辑器,是一款开源的markdown编辑器,感兴趣可以了解下载使用)。
STL相关
- STL(Standard Template Library),标准模板库
- STL从广义上分为:容器(container), 算法(algorithm), 迭代器(iterator)
- 容器和算法之间通过迭代器进行无缝连接
- STL几乎所有代码都采用模板类或模板函数
- 通常不对关联容器使用泛型算法。关键字是const这一特性意味着不能将关联容器传递给修改或重排容器元素的算法,因为这类算法需要向元素写入值,而set类型中的元素是const的,map中的元素是pair,其第一个成员是const的。
[[string]] [[总]] [[deque]] [[queue]] [[stack]] [[list]] [[set multiset]] [[mat multimap]]
STL 六大组件
分别为:容器,算法,迭代器,仿函数,适配器(配接器), 空间配置器
- 容器:各种数据结构如:vector,list,deque,set,map等。用来存放数据
- 算法:各种常用算法如:sort,find,copy,for_each等
- 迭代器:扮演了容器和算法之间的胶合剂
- 仿函数:行为类似函数,可作为算法的某种策略 (重载())[[c++类相关#仿函数]]
- 适配器:一种用来修饰容器或者仿函数或迭代器接口的东西
- 空间配置器:负责空间的配置和管理
容器,算法,迭代器
容器:置物之所也
STL容器就是将运用最广泛的一些数据结构实现出来
常用的数据结构:数组, 链表,树, 栈, 队列, 集合, 映射表 等
这些容器分为序列式容器和关联式容器两种:
- 序列式容器:强调值的排序,序列式容器中的每个元素均有固定的位置。
- 关联式容器:二叉树结构,各元素之间没有严格的物理上的顺序关系
算法:问题之解法也
- 有限的步骤,解决逻辑或数学上的问题,这一门学科我们叫做算法(Algorithms)
算法分为:质变算法和非质变算法。 - 质变算法:是指运算过程中会更改区间内的元素的内容。例如:拷贝,替换,删除等等
- 非质变算法:是指运算过程中不会更改区间内的元素内容,例如:查找、计数、遍历、寻找极值等等
迭代器:容器和算法之间粘合剂
- 提供一种方法,使之能够依序寻访某个容器所含的各个元素,而又无需暴露该容器的内部表示方式。
- 每个容器都有自己专属的迭代器
- 迭代器使用非常类似于指针,初学阶段我们可以先理解迭代器为指针
存放内置数据类型
#include <vector>
#include <algorithm>
void test01()
{
vector<int> vec;
for (int i = 0; i < 5; i++)
vec.push_back(i) // 尾插法
// c++11 新语法
for (const auto &v : vec)
cout << v << endl;
// 迭代器
vector<int>::iterator it = vec.begin();
vector<int>::const_iterator it = vec.cend();
// c++11 新
auto it = vec.begin();
}
存放自定义数据类型
- 传入的对象是什么类型那么迭代器所指向的就是什么
void test01()
{
vector<Person*> vec;
// 此时 v 为vector所传入的类型 即 Person*
for (const auto &v: vec)
cout << vec-> << " " << vec-> << endl;
}
容器嵌套容器
void test01()
{
vector<vector<int>> vec;
vector<int> v1;
vector<int> v2;
vector<int> v3;
for (int i = 0; i < 5; i++)
{
v1.push_back(i + 1);
v2.push_back(i + 2);
v3.push_back(i + 3);
}
vec.push_back(v1);
vec.push_back(v2);
vec.push_back(v3);
//for (auto it = vec.begin(); it != vec.end(); it++)
//{
// for (auto vit = it->begin(); vit != it->end(); vit++)
// cout << *vit << " ";
//}
for (const auto &v1 : vec)
{
for (const auto &v2: v1)
cout << v2 << " ";
cout << endl;
}
}
vector
- vector与普通数组的区别:数组不可以动态扩展,vector可
- vector的数据结构和数组类似,都是单端数组
动态扩展
- 并不是在原空间之后续接新空间,而是找更大的一块空间,然后拷贝原数据到新空间,释放原空间
- vector的迭代器支持随机访问
构造函数
函数原型
- vector<T> v;
- vector(v.begin(), v.end());
- vector(n, elem);
- vector(const vector &vec);
void test01()
{
vector<int> v1;
for (int i = 0; i < 10; i++)
v1.push_back(i);
printV(v1);
vector<int> v2(v1.begin(), v1.end());
printV(v2);
vector<int> v3(10, 100);
printV(v3);
vector<int> v4(v3);
printV(v4);
}
赋值操作
函数原型
- vector& operator=(const vector &vec);
- assign(beg, end);
- assign(n, elem);
void test02()
{
vector<int> v1;
for (int i = 0; i < 10; i++)
v1.push_back(i);
vector<int> v2;
v2 = v1;
printV(v2);
vector<int> v3;
v3.assign(v1.begin(), v1.end());
printV(v3);
vector<int> v4;
v4.assign(10, 100);
printV(v4);
}
容量和大小
函数原型
- empty();
- capacity();
- size();
- resize(int num); 重新指定容器的长度,若容器变长则以默认值填充新位置,如果容器变短则超出部分被删除
- resize(int num, elem); 以elem填充新位置
- shrink_to_fit(); 将 capacity 减为和 size 的同样大小
void test03()
{
vector<int> v1;
for (int i = 0; i < 10; i++)
v1.push_back(i);
if (!v1.empty())
{
cout << "capacity: " << v1.capacity() << endl;
cout << "size: " << v1.size() << endl;
}
v1.resize(20);
printV(v1);
v1.resize(14, 10);
printV(v1);
v1.resize(5);
printV(v1);
}
插入和删除
函数原型
- push_back(ele);
- pop_back();
- insert(const_iterator pos, ele);
- inster(const_iterator pos, int count, ele);
- erase(const_iterator pos);
- erase(const_iterator start, const_iterator end);
- clear();
void test04()
{
vector<int> v1;
for (int i = 0; i < 10; i++)
v1.push_back(i);
printV(v1);
v1.pop_back();
printV(v1);
//插入
v1.insert(v1.begin(), 100);
printV(v1);
v1.insert(v1.begin(), 2, 1000);
printV(v1);
//删除
v1.erase(v1.begin());
printV(v1);
v1.erase(v1.begin(), v1.end());
printV(v1);
v1.clear();
printV(v1);
}
数据存取
函数原型
- at(int idx);
- operator[];
- front();
- back();
void test05()
{
vector<int> v1;
for (int i = 0; i < 10; i++)
v1.push_back(i);
for (int i = 0; i < v1.size(); ++i)
cout << v1[i] << " ";
cout << endl;
for (int i = 0; i < v1.size(); ++i)
cout << v1.at(i) << " ";
cout << endl;
auto one = v1.front();
auto end = v1.back();
cout << one << " " << end << endl;
}
互换容器
两个容器的元素互换
函数原型
- swap(vec);
// swap 实际用途
void test07()
{
vector<int> v1;
for (int i = 0; i < 100000; i++)
v1.push_back(i);
cout << "capacity: " << v1.capacity() << endl; // 131072
cout << "size: " << v1.size() << endl; // 100000
v1.resize(3);
cout << "capacity: " << v1.capacity() << endl; // 131072
cout << "size: " << v1.size() << endl; // 3
// 巧用swap收缩内存
vector<int> (v1).swap(v1); // vector<int> (v1) 匿名对象 Person (p);
cout << "capacity: " << v1.capacity() << endl; // 3
cout << "size: " << v1.size() << endl; // 3
}
预留空间
减少vector在动态扩展容量时的扩展次数
函数原型
- reserve(int len); 容器预留len个元素长度,预留位置不初始化,元素不可访问
void test08()
{
vector<int> v1;
// 预留100000 的空间
v1.reserve(100000);
int num = 0;
int *p = nullptr;
for (int i = 0; i < 100000; i++)
{
v1.push_back(i);
if (p != &v1[0])
{
p = &v1[0];
num++;
}
}
cout << "num: " << num << endl; // 18 相当于分配了18次内存
}
string
本质
- string是c++风格的字符串,本质上是一个类
string和char *的区别 - char * 是一个指针
- string 是一个类,内部封装了 char * ,管理这个字符串,是一个char* 型容器
特点 - string 类封装了,find,copy,delete,replace,insert等方法
- string 管理 char* 所分配的内存,不用担心越界和取值越界等问题
string 构造函数
构造函数原型
- string();
- string(const char *s);
- string(const string &str);
- string(int n, char c);
void test01()
{
string s1;
const char *str = "hello world";
string s2(str);
cout << s2 << endl;
string s3(s2);
cout << "s3: " << s3 << endl;
string s4(10, 'a');
cout << "s4: " << s4 << endl;
}
string 赋值操作
赋值的函数原型
- string& operator=(const char *s);
- string& operator=(const string &s);
- string& operator=(char c);
- string& assign(const char *s);
- string& assign(const char *s, int n);
- string& assign(const string &s);
- string& assign(int n, char c);
void test02()
{
string str1;
str1 = "wuyan";
string str2;
str2 = str1;
string str3;
str3 = 'a';
string str4;
str4.assign("wuyan");
string str5;
str5.assign("wuyan12345", 5); // out put wuyan
string str6;
str6.assign(str5);
string str7;
str7.assign(10, 'w');
}
string 字符串拼接
函数原型
- string& operator+=(const char *str);
- string& operator+=(const char c);
- string& operator+=(const string &str);
- string& append(const char *s);
- string& append(const char *s, int n);
- string& append(const string &s);
- string& append(const string &s, int pos, int n);
void test03()
{
string str1("w");
str1 += "uyan";
str1 += '!';
string str2(" it`s so cool");
str1 += str2;
string str3("I");
str3.append(" love ");
// out put I love you
str3.append("you 12313", 3);
str3.append(str2);
str3.append(str2, 0, 3);
}
string 查找和替换
函数原型
- int find(const string &str, int pos = 0) const;
- int find(const char *, int pos = 0) const;
- int find(const char *, int pos = 0,int n) const;
- int find(const char c, int pos = 0) const;
- int rfind(const string &str, int pos = npos) const;
- int rfind(const char *, int pos = npos) const;
- int rfind(const char *, int pos, int n) const;
- int rfind(const char c, int pos = 0) const;
- string& replace(int pos, int n, const string &str);
- string& replace(int pos, int n, const char *);
void test04()
{
// 查找
string str1 = "abcdefgde";
// 返回下标,找到返回下标,未找到返回-1
int pos = str1.find("df");
// rfind 从后往左查
pos = str1.rfind("de");
// 替换
string str2 = "abcdefg";
str2.replace(1, 3, "1111"); // output a1111efg
}
string 字符串比较
- 字符串是根据ASCII码进行对比
函数原型 - int compare(const string &s) const;
- int compare(const char *s) const;
void test05()
{
string str1 = "xuyan";
string str2 = "wuyan";
if (str1.compare(str2) == 0)
cout << "相等" << endl;
else if (str1.compare(str2) > 0)
cout << "大于" << endl;
else
cout << "小于" << endl;
}
string字符串存取
- string 中 单个字符存取有两种
- char& operator[](int n);
- char& at(int n);
void test06()
{
string str1 = "wuyan";
for (int i = 0; i < str1.size(); i++)
cout << str1[i] << endl;
for (int i = 0; i < str1.size(); i++)
cout << str1.at(i) << endl;
str1[0] = 'x';
str1.at(1) = 'x';
}
string 中的插入和删除
函数原型
- string& insert(int pos, const char * s);
- string& insert(int pos, const string &str);
- string& insert(int pos, int n, char c);
- string& erase(int pos, int n = npos)
void test07()
{
string str = "hello";
str.insert(1, "111"); // h111ello
cout << str << endl;
str.erase(1, 3);
cout << str << endl; // hello
}
string 子串
函数原型
- string substr(int pos = 0, int n = npos) const;
void test08()
{
string email = "wuyan@qq.com";
int pos = email.find('@');
string subemial = email.substr(0, pos);
cout << subemial << endl; // wuyan
}
stack
- stack是一种先进后出(First in last out, FILO)的数据结构,它只有一个出口
- 只有栈顶可以访问,因此不支持遍历
常用接口
- 构造函数
- stack<T> stk;
- stack(const stack &stk);
- 赋值操作
- stack& operator=(const stack &stk);
- 数据存取
- push(elem);
- pop();
- top();
- 大小操作
- empty();
- size();
void test01()
{
stack<int> st;
for (int i = 0; i < 10; i++)
st.push(i);
if (!st.empty())
cout << "size: " << st.size() << endl;
while(!st.empty())
{
cout << "st.top(): " << st.top() << endl;
st.pop(); //出栈
}
cout << "size: " << st.size() << endl; // 0
}
set multiset
- 所有元素都会在插入时自动排序
- set和multiset属于关联式容器,底层结构是二叉树实现的
- set类型同时定义了iterator和const_iterator类型,但两种类型都只允许只读访问set中的元素
- 通常不对关联容器使用泛型算法(参见第10章)。关键字是const这一特性意味着不能将关联容器传递给修改或重排容器元素的算法,因为这类算法需要向元素写入值,而set类型中的元素是const的,map中的元素是pair,其第一个成员是const的。
区别
- set 不允许容器中有重复的元素
- multiset 反之
构造函数
函数原型
- set<T> st;
- set(const set &t);
- set& operator(const set &t);
void test01()
{
set<int> st;
st.insert(10);
st.insert(20);
st.insert(50);
st.insert(40);
st.insert(30);
st.insert(30);
set<int> st2(st);
set<int> st3;
st3 = st2;
}
大小和交换
函数原型
- size();
- empty();
- swap(st);
void test02()
{
set<int> st;
st.insert(10);
st.insert(20);
st.insert(50);
st.insert(40);
st.insert(30);
st.insert(30);
if (!st.empty())
cout << "size: " << st.size() << endl;
set<int> st2;
st2.insert(10);
st.swap(st2);
printS(st);
printS(st2);
}
插入和删除
构造函数
- insert(elem);
- clear();
- erase(pos);
- erase(beg, end);
- erase(elem);
void test03()
{
set<int> st;
st.insert(10);
st.insert(20);
st.insert(50);
st.insert(40);
st.insert(30);
st.insert(30);
st.erase(st.begin());
printS(st);
st.erase(30);
printS(st);
st.clear();
printS(st);
}
查找和统计
函数原型
- find(key); 查找key是否存在,若存在,返回该元素的迭代器,反之返回set.end()
- count(key);
void test04()
{
set<int> st;
st.insert(10);
st.insert(20);
st.insert(50);
st.insert(40);
st.insert(30);
st.insert(30);
set<int>::iterator pos = st.find(30);
if (pos != st.end())
cout << *pos << endl;
int num = st.count(30); // 对于set而言 不是1就是0
cout << num << endl;
}
区别
- set不可以插入重复的数据,即使插入也无效,multiset反之
- set插入数据的同时会返回插入结果,表示是否插入成功
- multiset不会检测数据,因此可以插入重复数据
void test05()
{
set<int> st;
pair<set<int>::iterator, bool> ret = st.insert(10);
if (ret.second)
cout << "OK!" << endl;
ret = st.insert(10);
if (ret.second)
cout << "OK!" << endl;
multiset<int> mst;
mst.insert(10);
mst.insert(10);
mst.insert(10);
printS(mst);
}
pair对组创建
#pair对组
- 成对出现的数据,利用对组可以返回两个数据
两种创建方式
- pair<type, type> p(value1, value2);
- pair<type, type> p = make_pair(value1, value2);
void test06()
{
pair<string, int> p("Tom", 20);
cout << "name: " << p.first << " age: " << p.second << endl;
pair<string, int> p2 = make_pair("Jerry", 20);
cout << "name: " << p2.first << " age: " << p2.second << endl;
}
排序
- set 容器默认从小到大排序,可以利用仿函数改变排序规则 #仿函数
内置数据类型
class Compare
{
public:
// 新标准下,必须加 const 以防止改变数据
bool operator()(int val1, int val2) const
{
return val1 > val2;
}
};
void test07()
{
set<int, Compare> st;
st.insert(10);
st.insert(20);
st.insert(50);
st.insert(40);
st.insert(30);
st.insert(30);
printSC(st);
}
自定义数据类型
class Person
{
public:
Person() = default;
Person(string name, int age) :
m_Name(name), m_Age(age)
{}
string m_Name;
int m_Age;
};
class Compare2
{
public:
bool operator()(const Person &p1, const Person &p2) const
{
return p1.m_Age > p2.m_Age;
}
};
void printS(const set<Person, Compare2> &s1)
{
for (set<Person, Compare2>::const_iterator it = s1.begin();
it != s1.end(); it++)
{
cout << "name: " << it->m_Name << " age: " << it->m_Age << endl;
}
}
void test08()
{
// 自定义数据类型都会指定排序规则
set<Person, Compare2> s1;
Person p1("play1", 23);
Person p2("play2", 22);
Person p3("play3", 29);
Person p4("play4", 21);
Person p5("play5", 22);
s1.insert(p1);
s1.insert(p2);
s1.insert(p3);
s1.insert(p4);
s1.insert(p5);
printS(s1);
}
queue
- **queue是一种先进先出(first in first out, FIFO)的数据结构,它有两个口
- 队列允许从一端新增数据,从另一端移除数据
- 队列只有对头和队尾可以被外界使用,不支持遍历
常用接口
- 构造函数
- queue<T> que;
- queue(const queue &que);
- 赋值操作
- queue& operator=(const queue &que);
- 数据存取
- push(elem);
- pop();
- back();
- front();
- 大小操作
- empty();
- size();
void test01()
{
queue<Person> que;
Person p1("wuyan1", 1);
Person p2("wuyan2", 2);
Person p3("wuyan3", 3);
que.push(p1);
que.push(p2);
que.push(p3);
if (!que.empty())
cout << "size: " << que.size() << endl;
while(!que.empty())
{
cout << "front(): " << que.front().m_Name << " " << que.front().m_Age << endl;
cout << "back(): " << que.back().m_Name << " " << que.back().m_Age << endl;
que.pop(); // 从对头移除一个元素
}
cout << "size: " << que.size() << endl;
}
map multimap
- map中所有元素都是pair
- pair中的一个元素是键值(key),起到索引作用,第二个元素为实值(value)
- 所有元素会根据键值自动排序
map/multimap属于关联式容器,底层结构是用二叉树实现的
#关联式容器
![[msedge_b6jI4jWOob.png]]
- 只有map类型(unordered_map、unordered_multimap、multimap和map)才定义了mapped_type。
- 当解引用一个关联容器迭代器时,我们会得到一个类型为容器的value_type的值的引用。对map而言,value_type是一个pair类型,其first成员保存const的关键字,second成员保存值
- 一个map的value_type是一个pair,我们可以改变pair的值,但不能改变关键字成员的值
- 对一个map使用下标操作,其行为与数组或vector上的下标操作很不相同:使用一个不在容器中的关键字作为下标,会添加一个具有此关键字的元素到map中。
优点
- 可以根据 key 值快速找到value值
区别 - map不允许容器中有重复的key值元素
- multimap 反之
构造和赋值
函数原型
构造
- map<T1, T2> mp;
- map(const map &mp);
赋值 - map& operator=(const map &mp);
void printM(map<int , int> &mp)
{
for (const auto &m :mp)
cout << "key: " << m.first << " value: " << m.second << endl;
cout << endl;
}
void test01()
{
map<int, int> m1;
m1.insert(pair<int, int>(1, 10));
m1.insert(pair<int, int>(3, 30));
m1.insert(pair<int, int>(2, 20));
printM(m1);
map<int, int> m2(m1);
printM(m2);
map<int, int> m3;
m3 = m2;
printM(m3);
}
大小和交换
函数原型
- size();
- empty();
- swap(mt);
void test02()
{
map<int, int> m1;
m1.insert(pair<int, int>(1, 10));
m1.insert(pair<int, int>(3, 30));
m1.insert(pair<int, int>(2, 20));
printM(m1);
if (!m1.empty())
cout << "size: " << m1.size() << endl;
map<int, int> m2;
m2.insert(pair<int, int>(8, 100));
m2.insert(pair<int, int>(7, 300));
m2.insert(pair<int, int>(6, 200));
m1.swap(m2);
printM(m1);
printM(m2);
}
插入和删除
函数原型
- insert(elem);
- clear();
- erase(pos);
- erase(beg. end);
- erase(key);
- void test03()
{
map<int, int> m1;
m1.insert(pair<int, int>(1, 10));
m1.insert(pair<int, int>(3, 30));
m1.insert(pair<int, int>(2, 20));
m1.insert(make_pair(4, 200));
m1.insert(map<int, int>::value_type(5, 200));
m1[7] = 100; // 不建议用这种方式
// 不建议插入,可以利用key访问value
cout << m1[7] << endl;
printM(m1);
m1.erase(m1.begin());
printM(m1);
m1.erase(7); //key
printM(m1);
m1.erase(m1.begin(), m1.end());
m1.clear();
printM(m1);
}
查找和统计
函数原型
- find(key); 查找key是否存在,若存在返回该键元素的迭代器,否则返回set.end()
- count(key); 统计key的元素个数
void test04()
{
map<int, int> m1;
m1.insert(pair<int, int>(1, 10));
m1.insert(pair<int, int>(3, 30));
m1.insert(pair<int, int>(2, 20));
map<int, int>::iterator pos = m1.find(3);
if ( pos != m1.end())
cout << "key: " << pos->first << " value: " << pos->second << endl;
cout << "count: " << m1.count(3) << endl;
}
排序
- 利用仿函数
class Compare
{
public:
bool operator()(int val1, int val2) const
{
return val1 > val2;
}
};
void printM(map<int , int, Compare> &mp)
{
for (const auto &m :mp)
cout << "key: " << m.first << " value: " << m.second << endl;
cout << endl;
}
void test05()
{
map<int, int, Compare> m1;
m1.insert(pair<int, int>(1, 10));
m1.insert(pair<int, int>(3, 30));
m1.insert(pair<int, int>(2, 20));
printM(m1);
}
案例
#include <iostream>
#include <vector>
#include <string>
#include <ctime>
#include <map>
using namespace std;
#define CHEHUA 0
#define MEISHU 1
#define YANFA 2
class Worker
{
public:
string m_Name;
int m_Salary;
};
void creat_worker(vector<Worker> &v)
{
string nameSeed = "ABCDEFGHIJ";
for (int i = 0; i < 10; i++)
{
Worker wk;
wk.m_Name = "员工 ";
wk.m_Name += nameSeed[i];
wk.m_Salary = rand() % 10000 + 10000;
v.push_back(wk);
}
}
void printV(vector<Worker> &vec)
{
for (const auto &v:vec)
cout << "姓名: " << v.m_Name << " 工资: " << v.m_Salary << endl;
}
void set_group(const vector<Worker> &vec, multimap<int, Worker> &m)
{
for (const auto &v:vec)
{
int depId = rand() % 3; // 0 1 2
m.insert(make_pair(depId, v));
}
}
void showWorkerByGroup(multimap<int, Worker> &m)
{
cout << "-----策划部门-----" << endl;
multimap<int, Worker>::const_iterator pos = m.find(CHEHUA);
int count = m.count(CHEHUA);
int index = 0;
for (; pos != m.end() && index < count; pos++, index++)
cout << "姓名: " << pos->second.m_Name << \
" 工资: " << pos->second.m_Salary << endl;
cout << "-----美术部门-----" << endl;
pos = m.find(MEISHU);
count = m.count(MEISHU);
index = 0;
for (; pos != m.end() && index < count; pos++, index++)
cout << "姓名: " << pos->second.m_Name << \
" 工资: " << pos->second.m_Salary << endl;
cout << "-----研发部门-----" << endl;
pos = m.find(YANFA);
count = m.count(YANFA);
index = 0;
for (; pos != m.end() && index < count; pos++, index++)
cout << "姓名: " << pos->second.m_Name << \
" 工资: " << pos->second.m_Salary << endl;
}
void test01()
{
srand((unsigned int) time(NULL));
// 1
vector<Worker> vw;
creat_worker(vw);
// 2
multimap<int, Worker> mw;
set_group(vw, mw);
// 3
showWorkerByGroup(mw);
}
int main()
{
test01();
return 0;
}
list
- 链表是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的
- 链表的组成:链表是由一系列节点组成的
- 节点的组成:一个是存储数据元素的数据域,另一个是存储下一个节点地址的指针域
- STL中的链表是一个双向循环链表
![[list.jpg]] - **链表的存储不是连续的内存空间,因此链表中的迭代器只支持前移和后移,属于双向迭代器
- 优点:可以相对快速的在任一位置进行插入和删除元素,采用动态内存分配,不会造成内存浪费和溢出
- 缺点:遍历速度较慢,占用空间较大
list有一个重要的性质:插入和删除操作都不会造成list迭代器的失效,这在vector中是不成立的
构造函数
函数原型
- list<T> lst;
- list(beg, end);
- list(n, elem);
- list(const list &lst);
void test01()
{
list<int> l1;
for (int i = 0; i < 5; i++)
l1.push_back(i);
list<int> l2(l1.begin(), l1.end());
list<int> l3(l2);
list<int> l4(10, 1000);
}
赋值和交换
函数原型
- assign(beg, end);
- assign(n, elem);
- list& operator=(const list &lst);
- swap(lst);
void test02()
{
list<int> l1;
for (int i = 0; i < 5; i++)
l1.push_back(i);
list<int> l2;
l2 = l1;
list<int> l3;
l3.assign(l2.begin(), l2.end());
list<int> l4;
l4.assign(5, 888);
l1.swap(l4);
}
大小操作
函数原型
- size();
- empty();
- resize(num);
- resize(num, elem);
void test03()
{
list<int> l1;
for (int i = 0; i < 5; i++)
l1.push_back(i);
if (!l1.empty())
cout << "size: " << l1.size() << endl;
l1.resize(2);
l1.resize(6, 10);
}
插入和删除
函数原型
- push_back(elem);
- pop_back();
- push_front(elem);
- pop_front();
- insert(pos, elem);
- insert(pos, n, elem);
- insert(pos, beg, end);
- clear();
- erase(beg, end);
- erase(pos);
- remove(elem); 删除容器中所有与elem匹配的元素
void test04()
{
list<int> l1;
for (int i = 0; i < 5; i++)
l1.push_back(i);
for (int i = 10; i < 15; i++)
l1.push_front(i);
l1.pop_back(); //尾删
l1.pop_front(); //头删
// l1.insert(l1.begin() + 1, 888); err 不支持随机访问
// list<int>::iterator it = l1.begin();
auto it = l1.begin();
l1.insert(++it, 888);
// 如果既支持 ++ 又支持 -- 说明是双向循环
l1.erase(l1.begin());
l1.remove(2); //删除所有和2匹配的元素
l1.clear();
}
- tips 如果既支持 ++ 又支持 - - 说明是双向循环,迭代器不可以 + 1的话,说明不支持随机访问
#随机访问迭代器
数据存取
函数原型
- front();
- back();
void test05()
{
list<int> l1;
for (int i = 0; i < 5; i++)
l1.push_back(i);
cout << "l1.front(): " << l1.front() << endl;
cout << "l1.back(): " << l1.back() << endl;
}
反转和排序
函数原型
- reverse();
- sort();
所有不支持随机访问迭代器的容器,不可以使用标准算法,它自己内部会提供一些算法
#随机访问迭代器
bool m_compare(int val1, int val2)
{
// 降序 就让第一个数大于第二个数
return val1 > val2;
}
void test06()
{
list<int> l1;
for (int i = 0; i < 5; i++)
l1.push_back(i);
l1.reverse(); // 反转相当于倒序 不是排序
printL(l1);
list<int> l2;
l2.push_back(3);
l2.push_back(2);
l2.push_back(0);
l2.push_back(9);
l2.push_back(1);
// sort(l2.begin(), l2.end()); err
l2.sort(m_compare); // 默认从小到大
printL(l2);
}
deque
- 双端数组,可以对头端进行插入删除操作
deque和vector的区别
- vector对于头部的插入删除效率低,数据量越大,效率越低
- deque相对于而言,对头部的插入删除速度比vector快
- vector访问元素时的速度会比deque快,这和两者的内部实现有关
- deque容器没有容量概念,因为它可以无限放数据
![[deque.jpg]]
内部实现原理
deque 内部有个中控器, 维护每段缓冲区中的内容,缓冲区存放真实数据
中控器维护每个缓冲区的地址,使得使用deque时像一片连续的内存空间
![[deque_中控器.jpg]]
- deque 的迭代器支持随机访问
构造函数
函数原型
- deque<int> deq;
- deque(beg, end);
- deque(n, elem);
- deque(const deque &deq);
void test01()
{
deque<int> d1;
for (int i = 0; i < 10; i++)
d1.push_back(i);
deque<int> d2(d1.begin(), d1.end());
deque<int> d3(10, 100);
deque<int> d4(d3);
}
赋值操作
函数原型
- deque& operator=(const deque &deq);
- assign(beg, end);
- assign(n, elem);
void test02()
{
deque<int> d1;
for (int i = 0; i < 10; i++)
d1.push_back(i);
// operator=
deque<int> d2;
d2 = d1;
deque<int> d3;
d3.assign(d1.begin(), d1.end());
deque<int> d4;
d4.assign(10, 100);
}
大小操作
函数原型
- deque.empty();
- deque.size();
- deque.resize(num);
- deque.resize(num, elem);
void test03()
{
deque<int> d1;
for (int i = 0; i < 10; i++)
d1.push_back(i);
if (!d1.empty())
// deque容器没有容量概念,因为它可以无限放数据
cout << "size: " << d1.size() << endl;
// resize
// d1.resize(15);
printD(d1);
d1.resize(15, 1);
d1.resize(5);
}
插入和删除
函数原型
- 两端插入操作
- push_back(elem);
- push_front(elem);
- pop_back();
- pop_front();
- 指定位置操作
- insert(pos, elem);
- insert(pos, n, elem);
- insert(pos, beg, end);
- clear();
- erase(beg, end);
- erase(pos);
void test04()
{
deque<int> d1;
for (int i = 0; i < 10; i++)
d1.push_front(i);
for (int i = 1; i < 10; i++)
d1.push_back(i);
d1.pop_back();
d1.pop_front();
d1.insert(d1.begin(), 1000);
d1.insert(d1.begin(), 2, 10000);
// 区间插入
deque<int> d2;
d2.push_back(1);
d2.push_back(2);
d2.push_back(3);
// 在d1 begin 位置 插入d2的begin 到 end 位置
d1.insert(d1.begin(), d2.begin(), d2.end());
}
// 删除
void test05()
{
deque<int> d1;
d1.push_back(10);
d1.push_back(20);
d1.push_back(30);
d1.push_back(40);
auto it = d1.begin();
it++;
d1.erase(it);
d1.erase(d1.begin(), d1.end());
d1.clear();
}
数据存取
函数原型
- at(int idx);
- operator[];
- front();
- back();
void test06()
{
deque<int> d1;
for (int i = 0; i < 10; i++)
d1.push_front(i);
for (int i = 0; i < d1.size(); i++)
cout << d1[i] << " ";
cout << endl;
for (int i = 0; i < d1.size(); i++)
cout << d1.at(i) << " ";
cout << endl;
cout << "front(): " << d1.front() << endl;
cout << "back(): " << d1.back() << endl;
}
排序
对于支持随机访问迭代器的容器,都可以利用sort算法排序
- 算法
- sort(iterator beg, iterator end) 对begin和end区间内元素进行排序
void test07()
{
deque<int> d1;
d1.push_back(10);
d1.push_back(20);
d1.push_front(100);
d1.push_front(1000);
printD(d1);
sort(d1.begin(), d1.end());
printD(d1);
}
案例
- 随机数 #随机数
- rand() % num + num
- 随机数种子
- 需要头文件<ctime>
- srand((unsigned int) time(NULL));
#include <iostream>
#include <string>
#include <vector>
#include <deque>
#include <ctime>
#include <algorithm>
using namespace std;
class Person
{
public:
Person() = default;
Person(string name, int score) :
m_Name(name), m_Score(score)
{
}
string m_Name;
int m_Score;
};
void creatPerson(vector<Person> &v)
{
string nameSeed = "ABCDE";
for (int i = 0; i < 5; i++)
{
string name = "Player";
name += nameSeed[i];
int score = 0;
Person p(name, score);
v.push_back(p);
}
}
void printPerson(const vector<Person> &vec)
{
for (const auto &v : vec)
cout << "name: " << v.m_Name
<< " score: " << v.m_Score << endl;
}
// 打分
void setScore(vector<Person> &vec)
{
for (vector<Person>::iterator it = vec.begin(); it != vec.end(); it++)
{
deque<int> _sco;
// 十个人打分
for (int i = 0; i < 10; i++)
{
int score = rand() % 41 + 60; // 随机数 60 ~ 100
_sco.push_back(score);
}
//cout << "name: " << it->m_Name << " score: " << endl;
//for (auto &d : _sco)
// cout << d << endl;
// 排序
sort(_sco.begin(), _sco.end());
// 去除最高分和最低分
// 通过排序后,进行尾删和头删。相当于去除最高分和最低分
_sco.pop_back();
_sco.pop_front();
// 取平均分
int sum = 0;
// c++11 范围for
for (auto &d : _sco)
sum += d;
int avg = sum / _sco.size();
// 平均分赋值给选手
it->m_Score = avg;
}
}
void test01()
{
// 随机数种子
srand((unsigned int) time(NULL));
vector<Person> vec;
creatPerson(vec);
printPerson(vec);
setScore(vec);
printPerson(vec);
}
int main()
{
test01();
return 0;
}
无序容器
新标准定义了4个无序关联容器(unordered associative container)。这些容器不是使用比较运算符来组织元素,而是使用一个**哈希函数**(hash function)和关键字类型的`==`运算符。在关键字类型的元素没有明显的序关系的情况下,无序容器是非常有用的。在某些应用中,维护元素的序代价非常高昂,此时无序容器也很有用。
-
除了hash管理操作外,无序容器依然有与有序容器相同的操作(find,insert)等
-
无序容器也有允许重复关键字的版本
-
通常可以用一个无序容器替换对应的有序容器,反之亦然。但是,由于元素未按顺序存储,一个使用无序容器的程序的输出(通常)会与使用有序容器的版本不同。
![[msedge_1QSiibx2od.png]] -
unordered_map 保存关键字-值对的容器,不允许重复关键字。
-
unordered_multimap 保存关键字-值对的容器,允许重复关键字。
-
unordered_multiset 保存关键字的容器,允许重复关键字。
-
unordered_set 保存关键字的容器,不允许重复关键字
常用算法
- 算法重要是由头文件<algorithm> <functional> <numeric>组成
- <algorithm> 是所有STL头文件中最大的一个,范围涉及到:比较,交换,查找,遍历操作,复制,修改等等
- <numeric>体积很小,只包括几个在序列上面进行简单数学运算的模版函数
- <functional>定义了一些类模版,用以声明函数对象
常用遍历算法
- for_each 遍历容器
- transform 搬运容器到另一个容器中
for_each
void print01(int val)
{
cout << val << " ";
}
class Print02
{
public:
void operator()(int val)
{
cout << val << endl;
}
};
void test01()
{
vector<int> v1;
for (int i = 0; i < 10; i++)
v1.push_back(i);
for_each(v1.begin(), v1.end(), print01);
cout << endl;
for_each(v1.begin(), v1.end(), Print02());
}
transform
- transform(iterator beg1, iterator end1, iterator beg2, _func);
class Transform
{
public:
int operator()(int v)
{
return v + 100;
}
};
class Print02
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
void test01()
{
vector<int> v1;
for (int i = 0; i < 10; i++)
v1.push_back(i);
vector<int> vTarget;
vTarget.resize(v1.size()); // 必须提前指定空间
transform(v1.begin(), v1.end(), vTarget.begin(), Transform());
for_each(vTarget.begin(), vTarget.end(), Print02());
}
常用查找算法
- find() -查找元素
- find_if() -按条件查找元素
- adjacent_find() -查找相邻重复元素
- binary_search() -二分查找
- count() -统计元素个数
- count_if() -按条件统计元素个数
find
查找指定元素,找到返回指定元素的迭代器,否则返回end()
- find(iterator beg, iterator end, value);
void test01()
{
vector<int> v;
for (int i = 0; i < 10; i++)
v.push_back(i);
auto pos = find(v.begin(), v.end(), 5);
if (pos != v.end())
cout << *pos << endl;
}
class Person
{
public:
Person() = default;
Person(string name, int age) :
m_Name(name), m_Age(age)
{}
//需要重载==
bool operator==(const Person &p) const
{
if (m_Name == p.m_Name && m_Age == p.m_Age)
return true;
return false;
}
string m_Name;
int m_Age;
};
void test02()
{
vector<Person> vp;
Person p1("play1", 10);
Person p2("play2", 20);
Person p3("play3", 30);
Person p4("play4", 40);
vp.push_back(p1);
vp.push_back(p2);
vp.push_back(p3);
vp.push_back(p4);
Person ptem("play2", 20);
auto pos = find(vp.begin(), vp.end(), ptem);
if (pos != vp.end())
cout << pos->m_Name << " " << pos->m_Age << endl;
}
find_if
- find_if(iterator beg, iterator end, _Pred); _Pred 函数或者谓词
class GreaterFive
{
public:
bool operator()(int val)
{
return val > 5;
}
};
void test01()
{
vector<int> v;
for (int i = 0; i < 10; i++)
v.push_back(i);
auto pos = find_if(v.begin(), v.end(), GreaterFive());
if (pos != v.end())
cout << *pos << endl;
}
class Person
{
public:
Person() = default;
Person(string name, int age) :
m_Name(name), m_Age(age)
{}
string m_Name;
int m_Age;
};
class Greater20
{
public:
bool operator()(const Person &p)
{
return p.m_Age > 20;
}
};
void test02()
{
vector<Person> vp;
Person p1("play1", 10);
Person p2("play2", 20);
Person p3("play3", 30);
Person p4("play4", 40);
vp.push_back(p1);
vp.push_back(p2);
vp.push_back(p3);
vp.push_back(p4);
auto pos = find_if(vp.begin(), vp.end(), Greater20());
if (pos != vp.end())
cout << pos->m_Name << " " << pos->m_Age << endl;
}
adjacent_find
- 查找相邻重复元素
- adjacent_find(iterator beg, iterator end);
void test01()
{
vector<int> v;
v.push_back(0);
v.push_back(2);
v.push_back(0);
v.push_back(3);
v.push_back(1);
v.push_back(3);
v.push_back(3);
auto pos = adjacent_find(v.begin(), v.end());
if (pos != v.end())
cout << *pos << endl;
}
binary_search
注意:在无序序列中不可以使用
- 二分查找 返回true 或 false
- bool binary_search(iterator beg, iterator end, value);
void test01()
{
vector<int> v;
for (int i = 0; i < 10; i++)
v.push_back(i);
if (binary_search(v.begin(), v.end(), 9))
cout << "OK!" << endl;
}
count
统计元素出现个数
- count(iterator beg, iterator end, value);
void test01()
{
vector<int> v;
v.push_back(10);
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(50);
v.push_back(50);
cout << count(v.begin(), v.end(), 10) << endl;
}
class Person
{
public:
Person() = default;
Person(string name, int age) :
m_Name(name), m_Age(age)
{}
bool operator==(const Person &p) const
{
if (m_Age == p.m_Age)
return true;
return false;
}
string m_Name;
int m_Age;
};
void test02()
{
vector<Person> vp;
Person p1("play1", 10);
Person p2("play2", 20);
Person p3("play3", 20);
Person p4("play4", 30);
vp.push_back(p1);
vp.push_back(p2);
vp.push_back(p3);
vp.push_back(p4);
Person p5("play5", 20);
cout << count(vp.begin(), vp.end(), p5) << endl;
}
count_if
- 按条件统计元素个数
- count_if(iterator beg, iterator end, _Pred);
class Creater20
{
public:
bool operator()(int val) const
{
return val > 20;
}
};
void test01()
{
vector<int> v;
v.push_back(10);
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(50);
v.push_back(50);
int num = count_if(v.begin(), v.end(), Creater20());
cout << num << endl;
}
class Person
{
public:
Person() = default;
Person(string name, int age) :
m_Name(name), m_Age(age)
{}
string m_Name;
int m_Age;
};
class CreaterPerson
{
public:
bool operator()(const Person &p) const
{
return p.m_Age > 10;
}
};
void test02()
{
vector<Person> vp;
Person p1("play1", 10);
Person p2("play2", 20);
Person p3("play3", 20);
Person p4("play4", 30);
vp.push_back(p1);
vp.push_back(p2);
vp.push_back(p3);
vp.push_back(p4);
cout << count_if(vp.begin(), vp.end(), CreaterPerson()) << endl;
}
常用排序算法
- sort
- random_shuffle -洗牌 指定范围内的元素随机调整次序
- merge -容器元素合并,并存储到另一容器中
- reverse - 反转指定范围的元素
sort
- sort(iterator beg, iterator end, _Pred);
void printV(int val)
{
cout << val << " ";
}
class SortV
{
public:
bool operator()(int val1, int val2) const
{
return val1 > val2;
}
};
void test01()
{
vector<int> v1;
v1.push_back(10);
v1.push_back(30);
v1.push_back(20);
v1.push_back(90);
v1.push_back(60);
sort(v1.begin(), v1.end());
for_each(v1.begin(), v1.end(), printV);
cout << endl;
//sort(v1.begin(), v1.end(), SortV());
sort(v1.begin(), v1.end(), greater<int>());
for_each(v1.begin(), v1.end(), printV);
}
random_shuffle
- 洗牌 将指定范围内的元素随机调整次序
- random_shuffle(iterator beg, iterator end);
void printV(int val)
{
cout << val << " ";
}
void test01()
{
srand((unsignde int) time(NULL));
vector<int> v1;
for (int i = 0; i < 10; i++)
v1.push_back(i);
// 打乱顺序
random_shuffle(v1.begin(), v1.end());
for_each(v1.begin(), v1.end(), printV);
}
merge
两个容器元素合并,并存储到另一个容器中 两个容器必须是有序的
- merge(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
void printV(int val)
{
cout << val << " ";
}
void test01()
{
vector<int> v1;
for (int i = 0; i < 10; i++)
v1.push_back(i);
vector<int> v2;
for (int i = 5; i < 15; i++)
v1.push_back(i);
// target
vector<int> vTarget;
vTarget.resize(v1.size() + v2.size());
merge(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
for_each(vTarget.begin(), vTarget.end(), printV);
}
reverse
将容器内的元素进行反转
- reverse(iterator beg, iterator end);
void printV(int val)
{
cout << val << " ";
}
void test01()
{
vector<int> v1;
for (int i = 0; i < 10; i++)
v1.push_back(i);
for_each(v1.begin(), v1.end(), printV);
reverse(v1.begin(), v1.end());
for_each(v1.begin(), v1.end(), printV);
}
常用拷贝和替换算法
- copy
- replace - 将容器内指定范围的旧元素修改为新元素
- replace_if - 同上 按照条件
- swap
copy
- copy(iterator beg1, iterator end1, iterator beg2);
void printV(int val)
{
cout << val << " ";
}
void test01()
{
vector<int> v1;
for (int i = 0; i < 10; i++)
v1.push_back(i);
vector<int> v2;
v2.resize(v1.size());
copy(v1.begin(), v1.end(), v2.begin());
for_each(v2.begin(), v2.end(), printV);
}
replace
将指定容器内的旧元素替换为新元素
- replace(iterator beg, iterator end, oldvalue, newvalue);
void printV(int val)
{
cout << val << " ";
}
void test01()
{
vector<int> v1;
for (int i = 0; i < 10; i++)
v1.push_back(i);
v1.push_back(5);
replace(v1.begin(), v1.end(), 5, 888);
for_each(v1.begin(), v1.end(), printV);
}
replace_if
将区间内满足条件的元素,替换为新元素
- replace_if(iterator beg, iterator end, _Pred, newvalue);
void printV(int val)
{
cout << val << " ";
}
class ReplaceV
{
public:
bool operator()(int val) const
{
return val > 0;
}
};
void test01()
{
vector<int> v1;
for (int i = 0; i < 10; i++)
v1.push_back(i);
v1.push_back(5);
replace_if(v1.begin(), v1.end(), ReplaceV(), 888);
for_each(v1.begin(), v1.end(), printV);
}
swap
- swap(container c1, container c2);
void printV(int val)
{
cout << val << " ";
}
void test01()
{
vector<int> v1;
for (int i = 0; i < 10; i++)
v1.push_back(i);
v1.push_back(10); // OK!
vector<int> v2;
for (int i = 5; i < 15; i++)
v2.push_back(i);
swap(v1, v2);
for_each(v1.begin(), v1.end(), printV);
cout << endl;
for_each(v2.begin(), v2.end(), printV);
}
常用算术生成算法
-
包含头文件为<numeric>
-
accumulate - 计算容器元素累计总和
-
fill - 向容器中添加元素
accumulate
计算容器元素累计总和
- accumulate(iterator beg, iterator end, value);
void test01()
{
vector<int> v1;
for (int i = 0; i <= 10000; i++)
v1.push_back(i);
// 参数3 是一个起始的累加值
int total = accumulate(v1.begin(), v1.end(), 10);
cout << total << endl;
}
fill
向容器中填充指定的元素
- fill(iterator beg, iterator end, value);
void printV(int val)
{
cout << val << " ";
}
void test01()
{
vector<int> v1;
v1.resize(10);
// 后期填充
fill(v1.begin(), v1.end(), 88);
for_each(v1.begin(), v1.end(), printV);
}
常用集合算法
- set_intersection - 求两个容器的交集 两个集合重复的元素
- set_union - 求两个容器的并集 两个集合不重复的元素
- set_difference - 求两个容器的差集
- 差集 如果是求 v1 和 v2 的差集:那么就是v1里面不是交集的一部分
- v2 和 v1 则反之
set_intersection
求交集
- set_intersection(iterator b1, iterator e1, iterator b2, iterator e2, iterator dest);
void printV(int val)
{
cout << val << " ";
}
void test01()
{
vector<int> v1;
vector<int> v2;
for (int i = 0; i < 10; i++)
{
v1.push_back(i); // 0 ` 9
v2.push_back(i + 5); // 5 ` 14
}
vector<int> vTarget;
//最特殊的情况 大容器包含小容器 ,开辟空间 取小容器
vTarget.resize(min(v1.size(), v2.size()));
// 返回end迭代器
vector<int>::iterator posEnd = set_intersection(v1.begin(), v1.end(),\
v2.begin(), v2.end(), vTarget.begin());
// for_each(vTarget.begin(), vTarget.end(), printV);
for_each(vTarget.begin(), posEnd, printV);
}
set_union
求两个集合的并集 两个集合必须是有序序列
- set_union(同上);
void printV(int val)
{
cout << val << " ";
}
void test01()
{
vector<int> v1;
vector<int> v2;
for (int i = 0; i < 10; i++)
{
v1.push_back(i); // 0 ` 9
v2.push_back(i + 5); // 5 ` 14
}
vector<int> vTarget;
//最特殊的情况 两个容器没有并集
vTarget.resize(v1.size() + v2.size());
// 返回end迭代器
vector<int>::iterator posEnd = set_union(v1.begin(), v1.end(),\
v2.begin(), v2.end(), vTarget.begin());
// for_each(vTarget.begin(), vTarget.end(), printV);
for_each(vTarget.begin(), posEnd, printV);
}
set_difference
求两个集合的差集, 两个集合必须是有序序列
- set_defference(iterator beg1, iterator beg2, …仿上);
void test01()
{
vector<int> v1;
vector<int> v2;
for (int i = 0; i < 10; i++)
{
v1.push_back(i); // 0 ` 9
v2.push_back(i + 5); // 5 ` 14
}
vector<int> vTarget;
// 最特殊的情况 两个容器没有交集,取两个容器中大的
vTarget.resize(max(v1.size(), v2.size()));
// 返回end迭代器
vector<int>::iterator posEnd = set_difference(v1.begin(), v1.end(),\
v2.begin(), v2.end(), vTarget.begin());
// for_each(vTarget.begin(), vTarget.end(), printV);
for_each(vTarget.begin(), posEnd, printV);
cout << endl;
// v2 v1
posEnd = set_difference(v2.begin(), v2.end(),\
v1.begin(), v1.end(), vTarget.begin());
// for_each(vTarget.begin(), vTarget.end(), printV);
for_each(vTarget.begin(), posEnd, printV);
}
迭代器相关
除了为每个容器定义的迭代器之外,标准库在头文件iterator中还定义了额外几种迭代器。这些迭代器包括以下几种。
- 插入迭代器(insert iterator):这些迭代器被绑定到一个容器上,可用来向容器插入元素
- 流迭代器(stream iterator):这些迭代器被绑定到输入或输出流上,可用来遍历所关联的IO流。
- 反向迭代器(reverse iterator):这些迭代器向后而不是向前移动。除了forward_list之外的标准库容器都有反向迭代器。
- 移动迭代器(move iterator):这些专用的迭代器不是拷贝其中的元素,而是移动它们。
流迭代器
// istream_iterator
void test01()
{
vector<int> vec;
istream_iterator<int> in(cin); // 指定流
istream_iterator<int> int_eof; // 默认构造为尾迭代器
while (in != int_eof)
vec.push_back(*in++);
}
void test02()
{
istream_iterator<int> in(cin), eof;
cout << accumulate(in, eof, 0) << endl;
}
反向迭代器相关问题
![[Pasted image 20231103195629.png]]
- 反向迭代器,在使用时会反向处理,达不到预期效果(详见代码), 可以使用成员函数base将其转换回普通迭代器
![[Pasted image 20231103195708.png]] - 反向迭代器的目的是表示元素范围,而这些范围是不对称的,这导致一个重要的结果:当我们从一个普通迭代器初始化一个反向迭代器,或是给一个反向迭代器赋值时,结果迭代器与原迭代器指向的并不是相同的元素。
// 反向迭代器
void test03()
{
string str = "hello, world, wuyan";
auto pos = find(str.cbegin(), str.cend(), ',');
cout << string(str.cbegin(), pos) << endl; // helloc
auto rpos = find(str.crbegin(), str.crend(), ',');
cout << string(str.crbegin(), rpos) << endl; // nayuw
// 将reverse_iterator 转换为一个普通迭代器,得到一个正向迭代器
cout << string(rpos.base(), str.cend()) << endl; // wuyan
}
五种迭代器类别
- 输入迭代器:只读,不写,单遍扫描,只能递增
- 输出迭代器:只写,不读,单遍扫描,只能递增
- 前向迭代器:可读写,多遍扫描,只能递增
- 双向迭代器:可读写,多遍扫描,可递增递减
- 随机访问迭代器:可读写,多遍扫描,支持全部迭代器运算
#五种迭代器类别