好友
阅读权限10
听众
最后登录1970-1-1
|
本帖最后由 NameQuin 于 2023-5-23 16:35 编辑
STL初识STL基本概念STL(Standard Template Library),标准模板库STL从广义上分为 容器(container)、算法(algorithm)、迭代器(iterator)容器和算法之间通过迭代器进行无缝连接STL几乎所有代码都采用了模板类或者模板函数 STL六大组件容器(Containers)- 各种数据结构,如vecotr、list、deque、set、map等,用来存放数据
- 常用的数据结构:数组、链表、树、栈、队列、集合、映射等;
- 分类
- 序列式容器:强调值的排序,序列式容器中的每个元素均有固定的位置
- 关联式容器:二叉树结构,各元素之间没有严格的物理上的顺序关系
算法(Algorithms)- 各种常用算法,如sort、find、copy、for_each等
- 分类
- 质变算法:运算过程中会更改区间内的元素内容。如拷贝、替换、删除等
- 非质变算法:运算过程中不会更改区间内的元素内容。例如查找、计数、遍历、寻找极值等。
迭代器(Iterators)- 扮演了容器与算法之间的胶合剂
- 提供一种方法,使之能够依序寻访某个容器所含的各个元素,而又无需暴露该容器的内部表示方法。
- 每个容器都有自己专属的迭代器
- 算法需要通过迭代器才能访问到容器的内容。
种类 | 功能 | 支持运算 | 输入迭代器 | 对数据的只读访问 | 只读,支持++、==、!= | 输出迭代器 | 对数据的只写访问 | 只写,支持++ | 前向迭代器 | 读写操作,并能向前推进迭代器 | 读写,支持++、==、!= | 双向迭代器 | 读写操作,并能向前和向后推进迭代器 | 读写,支持++、-- | 随机访问迭代器 | 读写操作,可以以跳跃的方式访问任意数据 | 读写,支持++、--、[n]、-n、<、<=、>、>= | 仿函数(Functors)适配器(Adapters)分配器(Allocators)Vector初识- 容器:vector
- 算法:for_each
- 迭代器:verctor<\int>::iterator
[C++] 纯文本查看 复制代码 #include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
​
void myPrint(int val)
{
cout<<val<<endl;
}
​
void test01()
{
//创建了一个vecotr容器
vector<int> v;
//向容器插入数据
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
//通过迭代器访问容器中的数据
vector<int>::iterator itBegin = v.begin();//起始迭代器,指向容器中的第一个元素
vector<int>:;iterator itEnd = v.end();//结束迭代器,指向容器中的最后一个元素的下一个位置
//第一种遍历方式
while(itBegin!=itEnd)
{
cout<<*itBegin<<endl;
itBegin++;
}
//第二种遍历方式
for(vector<int>::iterator it= v.begin();it!=v.end();it++)
{
cout<<*itBegin<<endl;
}
//第三种遍历方式
for_each(v.begin(),v.end(),myPrint)
}
[C++] 纯文本查看 复制代码 //Vector容器中存放自定义数据类型
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
​
class Person
{
public:
Person(string name,int age)
:m_Name(name),m_Age(age)
{}
string m_Name;
int m_Age;
};
​
void test01()
{
vector<Person> v;
Person p1("aaa",10);
Person p2("bbb",20);
Person p3("ccc",30);
Person p4("ddd",40);
Person p5("eee",50);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
v.push_back(p5);
for(vector<Person>::iterator it=it.begin();it!=v.end();it++)
{
cout<<(*it).m_Name<<(*it).age<<endl;
cout<<it->m_Name<<it->age<<endl;
}
}
​
void test02(){
vector<Person*> v;
Person p1("aaa",10);
Person p2("bbb",20);
Person p3("ccc",30);
Person p4("ddd",40);
Person p5("eee",50);
v.push_back(&p1);
v.push_back(&p2);
v.push_back(&p3);
v.push_back(&p4);
v.push_back(&p5);
for(vector<Person*>::iterator it=it.begin();it!=v.end();it++)
{
cout<<(*it)->m_Name<<(*it)->age<<endl;
}
}
[C++] 纯文本查看 复制代码 //容器嵌套容器
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
​
void test01()
{
vector<vector<int>> v;
vector<int> v1;
vector<int> v2;
vector<int> v3;
vector<int> v4;
for(int i=0;i<4;i++)
{
v1.pusu_back(i+1);
v2.pusu_back(i+2);
v3.pusu_back(i+3);
v4.pusu_back(i+4);
}
v.push_back(v1);
v.push_back(v2);
v.push_back(v3);
v.push_back(v4);
//遍历
for(vector<vector<int>>::iterator it=v.begin();it!=v.end();it++)
{
for(vector<int>::iterator vit = (*it).begin();vit!=(*it).end();vit++)
{
cout<<*vit<<"\t";
}
cout<<endl;
}
}
STL常用容器string容器本质string 是一个类,内部封装了 char*,管理这个字符串,是一个char*型的容器。特点- 封装了很多成员方法,如查找find,拷贝copy,删除delete,替换replace,插入insert
- string管理char*所分配的内存,不用担心复制越界或取值越界等,由类内部进行负责。
string构造函数- string(); //创建一个空字符串string(const char* s); //使字符串s初始化
- string(const string& str) //使用一个string对象初始化另一个string对象
- string(int n, char c) //使用n个字符c初始化
string的赋值操作- sting& operator=(const char* s); //char*类型字符串 赋值给当前的字符串
- string &operator=(const string &s); //把字符串s赋值给当前字符串
- string& operator=(char c); //字符赋值给当前字符串
- string& assign(const char* s); //把字符串s赋值给当前字符串
- string& assign(const char* s,int n); //把字符串s的前n个字符赋值给当前字符串
- string& assign(const string& s); //把字符串s赋值给当前字符串
- string& assign(int n, char c); //把n个字符c赋给当前字符串
[C++] 纯文本查看 复制代码 sting str1;
str1 = "hello world";
string str2;
str2 = str1;
string str3;
str3 = 'a';
string str4;
str4.assign("hello world");
string str5;
str5.assign("hello world",5);
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); //把字符串s连接到当前字符串结尾
string& append(const char* s,int n); //把字符串s的前n个字符连接到当前字符串结尾
string& append(const string &s); //同operator+=(const string& str);
string& append(const string &s,int pos,int n); //字符串s从pos开始的n个字符连接到字符串结尾
string str1 = "I";
str1 += "love c++";
str1 += '&';
string str2 = "DOTA2 SC2";
str1 += str2;
string str3 = "I";
str3.append("love");
str3.append("dotaaslnggg",4);
str3.append(str2,0,4);string字符串查找和替换
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,const char* s); //替换从pos开始n个字符为字符串s
void test01(){
string str1 = "abcdefg";
int pos = str1.find("de"); //pos = 3
int pos = str1.find("df"); //pos = -1
str1 = "abcdefgde"
int pos = str1.rfind("de"); //pos = 7
}
​
void test02()
{
string str1 = "abcdefg";
str1.replace(1,3,"1111"); //str1 = a1111efg
}
string字符串比较- 首个不一样的
- int compare(const string &s) const;
- int compare(const char* s) const;
string字符存取- char& operator[](int n)
- char& at(int n)
string插入和删除- string& insert(int pos,const char* s);
- string& insert(int pos,const string& str); //插入字符串
- string& insert(int pos,int n,const char* s); //在指定位置插入n个字符c
- string& erase(int pos,const char* s); //删除从pos开始的n个字符
string子串- string substr(int pos = 0, int n = npos) const; //返回由pos开始的n个字符串组成的字符串
vector容器与数组相似,也称为单端数组;与数组的区别- 数组是静态空间,vector可以动态扩展;
- 动态扩展并不是在原空间之后续接新空间,而是找更大的空间,然后将原数据拷贝到新空间,释放原空间。
vector容器的迭代器是支持随机访问的迭代器。vector构造函数- vector<T> v; //采用模板实现类实现,默认构造函数
- vector(v.begin(),v.end()); //将v[begin(),end())区间中的元素拷贝给本身
- vector(n,elem); //构造函数将n个elem拷贝给本身
- vector(const vector &vec); //拷贝构造函数
[C++] 纯文本查看 复制代码 vector<int> v1;
for(int i =0;i<10;i++)
v1.push_back(i);
​
vector<int> v2(v1.begin(),v1.end());
​
vector<int> v3(10,100); //10个100
vector<int> v4(v3);
vector赋值操作- vector& operator=(const vector &vec); //重载等号操作符
- assign(beg,end); // 将[beg,end)区间中的数据拷贝赋值给本身
- assign(n,elem); //将n个elem拷贝赋值给本身。
[C++] 纯文本查看 复制代码 vector<int> v1;
for(int i =0;i<10;i++)
v1.push_back(i);
​
vector<int> v2;
v2 = v1;
​
vector<int> v3;
v3.assign(v1.begin(),v1.end());
​
vector<int> v4;
v4.assign(10,100);
vector容量和大小- bool empty(); //判断容器是否为空
- int capacity(); //容器的容量
- size(); //返回容器中元素的个数
- resize(int num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
- resize(int num,elem); //重新指定容器的长度为num,若容器变长,则以elem填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
[C++] 纯文本查看 复制代码 vector<int> v1;
for(int i =0;i<10;i++)
v1.push_back(i);
v1.empty(); //为真代表容器为空
int capacity = v1.capacity(); //capacity = 13
int size = v1.size(); //size = 10
v1.resize(15); //默认用0来填充
v1.resize(15,100);
vector插入和删除- push_back(ele);
- pop_back();
- insert(const_iterator pos,ele); //迭代器指向位置pos插入元素ele
- insert(conset_iterator pos,int count,ele); //迭代器指向位置pos插入count个元素ele
- erase(const_iterator pos); //删除迭代器指向的元素
- erase(const_iterator start,const_iterator end); //删除迭代器从start到end之间的元素
- clear();
[C++] 纯文本查看 复制代码 vector<int> v1;
for(int i =0;i<10;i++)
v1.push_back(i);
​
v1.insert(v1.begin(),100);
v1.insert(v1.begin(),2,200);
​
v1.erase(v1.begin());
v1.erase(v1.begin(),v1.end());
vector数据存取- at(int idx); //返回索引idx所指的数据
- operator[]; //返回索引idx所指的数据
- front(); //返回容器的第一个数据
- back(); //返回容器的最后一个数据
vector互换容器- swap(vec); //将vec与本身的元素互换 ‘
[C++] 纯文本查看 复制代码 vector<int> v1;
for(int i =0;i<10;i++)
v1.push_back(i);
vector<int> v2;
for(int i =10;i>0;i--)
v1.push_back(i);
​
v1.swap(v2);
​
//巧用swap可以收缩内存空间
vector<int> v1;
for(int i =0;i<100000;i++)
v1.push_back(i);
v1.capacity(); //13xxxx
v1.size(); //100000
​
v1.resize(3);
v1.capacity(); //13xxxx
v1.size(); //3
​
vector<int>(v1).swap(v1); //vector<int>(v1) 拷贝构造函数创建匿名对象
v1.capacity(); //3
v1.size(); //3
vector预留空间减少vector在动态扩展容量时的扩展次数- reserve(int len); //容器预留len个元素长度,预留位置不初始化,元素不可访问。
//统计开辟空间次数
[C++] 纯文本查看 复制代码 vector<int> v1;
int num = 0;
int *p = NULL;
​
//加上v1.reserve(100000)后,num =1
for(int i =0;i<100000;i++)
{
v1.push_back(i);
if(p!=&v1.font())
{
p = &v1.font();
num++;
}
}
//num = 30
deque容器双端队列,可以对头端进行插入删除等操作;与vector的区别- vector对于头插\删效率低,deque更快
- vector访问元素时的速度会比deque快。这是内部实现决定的。
deque的迭代器支持随机访问。deque内部工作原理deque内部有个中控器,维护每段缓冲区中的内容,缓冲区中存放真实数据。中控器维护的是每个缓冲区的地址,使得使用deque时像一片连续的内存空间。 deque构造函数- deque<T>(); //默认构造形式
- deque(beg,end); //构造函数将[beg,end)区间中的元素拷贝给本身
- deque(n,elem); //构造函数将n个elem拷贝给本身
- deque(const deque &deq); //拷贝构造函数
deque赋值操作- deque& operator=(const deque &deq);
- assign(beg,end);
- assign(n,elem);
deque大小操作- bool empty();
- size();
- resize(int num);
- resize(int num,elem);
deque插入和删除两端操作- push_back(elem);
- push_front(elem);
- pop_back();
- pop_front()
指定位置操作- insert(int pos,elem); //在pos位置插入一个elem元素的拷贝,返回新数据的位置
- insert(int pos,int count,elem); //在pos位置插入n个elem数据,无返回值
- insert(int pos,begin,end); //在pos位置插入[begin,end)区间的数据,无返回值
- clear()
- erase(beg,end); //删除[beg,end)区间的数据,返回下一个数据的位置
- erase(int pos); //删除pos位置的数据,返回下一个数据的位置
deque数据存取- at(int idx);
- operator[];
- front();
- back();
deque排序- sort(iterator begin,iterator end); //对begin和end之间的元素进行排序,默认是升序
- vector也可以使用这个算法排序
stack容器stack构造函数- stack<T> stk;
- stack(const stack &stk)
stack赋值操作- operator=(const stack& stk);
stack大小操作stack数据存取- push(elem);
- pop();
- Elem top();
queue容器queue构造函数- queue<T> que;
- queue(const queue& que)
queue赋值操作- operator=(const queue& que);
queue大小操作queue数据存取- push(elem);
- pop();
- back(); //返回队尾元素
- font(); //返回队头元素
list容器链表,由一系列结点构成。结点:由存储数据元素的数据域和指向下一个结点地址的指针域构成。list是一个双向循环链表 List的插入和删除都不会造成原list迭代器的失效,这在vector中是不成立的。list构造函数- list<T> lst;
- list(beg,end);
- list(n,elem);
- list(const list& lst);
list赋值与交换- assign(beg,end);
- assign(n,elem);
- list& operator=(const list& lst);
- swap(list& lst);
list大小操作list数据插入和删除- push_back(elem);
- pop_back();
- push_front(elem);
- pop_front();
- insert(pos,elem); //返回新数据的位置
- insert(pos,n,elem);
- clear();
- erase(beg,end);
- erase(pos); //返回下一个数据的位置
- remove(elem);
list数据存取不可以用at() 和[]访问;迭代器不支持随机访问;list<int>::iterator it = l1.begin();it++;it --; //都可以it =it +1; //不可以,不支持随机访问。 list反转和排序- reverse(); //反转链表
- sort(); //排序链表
所有不支持随机访问迭代器的容器,不可以用排序算法。这里sort是成员函数 set/multiset容器set/multiset是关联式容器,底层结构是二叉树实现。所有元素都会在插入时自动被排序- set和multiset的区别
- set不允许容器中有重复的元素
- multiset允许容器中有重复元素
set构造和赋值- set<T> st;
- set(const set& st);
- set& operator=(const set& st);
set大小和交换set插入和删除- insert(elem);
- clear();
- erase(pos);
- erase(beg,end);
- erase(elem);
set查找和统计- find(key); //查找key是否存在,如果存在,返回该键的元素的迭代器;若不存在,返回set.end();
- count();
pair对组创建成对出现的数据,利用对组可以返回两个数据。- pair<type,type> p(value1,value2);
- pair<type,type> p = make_pair(value1,value2);
[C++] 纯文本查看 复制代码 pair<string,int>p("tom",20);
cout<<p.first<<p.second;
​
pair<string,int>p2 = make_pair("Jerry",30);
cout<<p2.first<<p2.second;
set容器排序[C++] 纯文本查看 复制代码 class MyCompare
{
public:
bool operator()(int v1,int v2)
{
return v1>v2;
}
}
​
set<int,MyCompare>s2;//自定义数据类型排序
class Person
{
public:
Peson(string name,int age)
:m_Name(name),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;
}
}
Person p1("刘备",24);
Person p2("关羽",22);
Person p3("张飞",20);
​
set<Person,ComparePerson> s;
s.insert(p1);
s.insert(p2);
s.insert(p3);
map/multimap容器- map中所有元素都是pair;
- pair中第一个元素为key(键)值,作为索引使用,第二个元素为value值
- 所有元素都会根据元素的键值自动排序
同样是关联式容器,底层结构是二叉树。map和multimap的区别- map不允许容器中有重复的key值元素
- multimap允许容器中有重复key值元素
map构造和赋值- map<T1,T2> mp;
- map(const map mp);
- map& operator=(const map& mp);
map大小和交换map插入和删除- insert(elem);
- clear();
- erase(pos);
- erase(beg,end);
- erase(key);
[C++] 纯文本查看 复制代码 map<int,int>m;
m.insert(pair<int,int>(1,100));
m.insert(make_pair(2,200));
m.insert(map<int,int>::value_type(3,300));
m[4] = 40;
map查找和统计map容器排序STL函数对象函数对象函数对象(仿函数)是一个类,不是一个函数。- 重载函数调用操作符的类,其对象常称为函数对象;
- 函数对象使用重载的()时,行为类似函数调用,也叫仿函数。
函数对象在使用时,可以像普通函数那样调用,可以有参数,可以有返回值。函数对象超出普通函数的概念,函数对象可以有自己的状态。函数对象可以作为参数传递。谓词- 返回bool类型的仿函数称为谓词;
- 如果operator()接受一个参数,那么叫做一元谓词
- 如果operator()接受两个参数,那么叫做二元谓词
内建函数对象使用内建函数对象,需要引入头文件#include<functional>算术仿函数实现四则运算- template<class T> T plus<T>;
- template<class T> T minus<T>;
- template<class T> T multiplies<T>;
- template<class T> T divides<T>;
- template<class T> T modulus<T>; //取模
- template<class T> T negate<T>; //取反
[C++] 纯文本查看 复制代码 negate<int> n;
n(50); //-50
​
plus<int> p;
p(10,20); //30
关系仿函数实现关系对比- template<class T> bool equal_to<T>;
- template<class T> bool not_equal<T>;
- template<class T> bool greater<T>;
- template<class T> bool greater_equal<T>;
- template<class T> bool less<T>;
- template<class T> bool less_equal<T>;
逻辑仿函数- template<class T> bool logical_and<T>;
- template<class T> bool logical_or<T>;
- template<class T> bool logical_not<T>;
STL常用算法主要由头文件<algorithm>、 <numeric>、<functional>组成<algorithm>:是所有STL头文件最大的一个,范围涉及到比较、交换、查找、遍历操作、复制、修改等等。 <numeric>:体积很小,只包括几个在序列上面进行简单数学运算的模板函数。<functional>:定义了一些模板类,用以声明函数对象。常用遍历算法- for_each(iterator beg,iterator end,_func) //遍历容器
- beg 起始迭代器
- end 结束迭代器
- _func 函数或者函数对象
- transform(iterator beg1,iterator end1,iterator beg2,_func) //搬运容器到另一个容器中
- beg1 源容器的起始迭代器
- end1 源容器的起始迭代器
- beg2 目标容器的起始迭代器
- _func 函数或者函数对象
常用查找算法- find //查找元素
- 查找指定元素,找到返回指定元素的迭代器,找不到返回结束迭代器
- find(iterator beg,iterator end,value)
- value 查找的元素
- 自定义数据类型需要重载 ==
- find_if //按条件查找元素
- 按条件查找元素,找到返回指定元素的迭代器,找不到返回结束迭代器
- find_if(iterato beg,iterator end,_Pred)
- _Pred 函数或者谓词(返回bool型的仿函数)
- adjacent_find //查找相邻重复元素
- 查找相邻重复元素,返回相邻元素的第一个位置的迭代器
- adjacent_find(iterator beg,iterator end);
- binary_search //二分查找法
- 二分法查找指定元素,找到返回true,找不到返回false
- 在 无序序列中不能使用
- bool binary_search(iterator beg,iterator end,value)
- count //统计元素出现次数
- count(iterator beg, iterator end,value)
- value统计的元素
- 自定义数据类型需要重载 ==
- count_if //按条件统计元素个数
- count_if(iterator beg, iterator end, _Pred)
- _Pred 谓词
常见排序算法- sort
- 对容器内元素进行排序
- sort(iterator beg,iterator end,_Pred)
- _Pred谓词
- random_shuffle
- 指定范围内的元素随机调整次序
- random_shuffle(iterator beg,iterator end)
- 使用时最好加上随机数种子srand((unsigned int)time(NULL));
- merge
- 两个容器合并,并存储到另一容器中
- 两个容器必须是有序的
- merge(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dst)
- 目标容器需要提前开辟空间vtarget.resize(v1.size()+v2.size())
- reverse
- reverse(iterator beg,iterator end)
常用拷贝和替换算法- copy
- copy(iterator beg,iterator end,iterator dst);
- 将源容器指定范围的数据拷贝到目标容器
- replace
- replace(iterator beg,iterator end,old_value,new_value)
- replace_if
- replace_if(iterator beg,iterator end,_Pred,newvalue)
- 满足条件的替换成指定元素
- swap
- swap(container c1,container c2)
- 同种类型的容器
常用算术生成算法 使用#include <numeric>- accumulate
- 计算容器元素累计总和
- accumulate(iterator beg,iterator end,value)
- value:起始累加值
- fill
- fill(iterator beg,iterator end,value)
常用集合算法- set_intersection
- 求两个集合交集
- set_intersection(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest);
- 两个集合必须是有序序列
- 目标容器需要提前开辟空间
- vtarget.resize(min(v1.size(),v2.size()))
- 最特殊的情况,大容器包含小容器,开辟空间取小的size即可。
- set_union
- 求两个集合并集
- set_union(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest);
- 两个集合必须是有序序列
- 目标容器需要提前开辟空间
- vtarget.resize(min(v1.size()+v2.size()))
- 最特殊的情况,两个容器没有交集,并集就是两个容器相加
- set_difference
- 求两个集合差集
- set_difference(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest);
- 两个集合必须是有序序列
- 目标容器需要提前开辟空间
- vtarget.resize(max(v1.size(),v2.size()))
- 最特殊的情况,两个容器没有交集,取两个容器中大的size
|
|