C++中的STL
STL(标准模板库)在广义上分为:容器,算法,迭代器
容器和算法之间通过迭代器进行无缝衔接
STL大体上分为六大组件:分别为容器,算法,迭代器,仿函数,适配器,空间配置器
- 容器:各种数据结构
- 算法:各种常用的算法
- 迭代器:扮演了容器和算法间的桥梁
- 仿函数:行为类似函数
- 适配器:修饰容器或者仿函数或者迭代器接口的东西
- 空间配置器:负责空间的配置和管理
1.实例
头文件:#include<vector>
容器:vector : 语法:vector<数据类型> 容器名;
方法:插入数据:容器名.push_back(数据);
迭代器:
vector<int>::iterator itBegin = v.begin();//定义起始迭代器,指向容器的第一个位置
vector<int>::iterator itEnd = v.end(); //结束迭代器,指向容器最后一个元素的下一个位置
2.string容器
string是一个类,类内部封装了char*,并且封装了多个成员方法
构造函数
- string():构造一个空的字符串 如:string str;
- string(const char *s):使用字符串s来初始化·
- string(const string &str)使用另一个string来初始化这个string对象
- string(int n,char c)使用n个c来初始化对象
赋值操作
方法1
void test01()
{
string str1;
str1 = "hello world"
}
方法2
void test01()
{
string str2;
str2 = str1;
}
方法3
void test01()
{
string str3;
str3 = 'a';
}
方法4
void test01()
{
string str4;
str4.assgin("hello world");
}
方法5
void test01()
{
string str5;
str5.assgin("hello world",5);
}
方法6
void test01()
{
string str6;
str6.assgin(str5);
}
方法7
void test01()
{
string str7;
str7.assgin(5,'x');
}
字符串拼接
void text01()
{
string str1 = "wjm";
str1 += "041006";
}
void text01()
{
string str2 = "wjm04100";
str1 += '6';
}
void text01()
{
string str3 = "041006";
str1 += str3;
}
剩下的使用append进行追加不具例子
和上面使用assgin进行赋值操作相差不大
查找与替换
查找
void test01()
{
string str1 = "wjm041006";
str1.find("04");//返回从零开始计数的初始位置,没有的话返回 -1
}
rfind同find的区别
rfind从右向左查找
find从左向右查找
替换操作
void test01()
{
string str1 = "wjm041006";
str1.replace(0,2,"wwww");
}
//这个的输出结果为wwww041006
字符串比较
= 返回0
> 返回1
< 返回 -1
void test01()
{
string str1 = "hello";
string str2 = "hello";
cout << str1.compare(str2) << endl;
}
//输出0;
//介绍一下字符串比较规则
//从第一个字符开始向后比较,如果两个字符对应位置相等,继续向后比较
//如果不相等,那么根据ascll值进行比较
string字符的存取
上面的方法同数组类似
下面的通过at方法
void test01()
{
string str1 = "wjm041006"
cout<<str1.at(0)<<endl;
}
//输出w
插入与删除
void test01()
{
string str = "wjm041006";
str.insert(1,"www");
str.erase(1,3);
}
//输出结果为wjm041006
子串获取
函数原型
string substr(int pos = 0,int n = npos)const;
void test01()
{
string str = "wjm041006";
string substr = str.substr(0,2);
cout<<substr<<endl;
}
//输出结果为wjm
3.vector容器
vector数据结构和数组非常类似,也称为单端数组
不同之处在于vector可以动态扩展
其动态扩展并不是在原空间之后续接新空间,而是寻找更大的内存空间进行拷贝,随后释放原空间
构造函数
void test01()
{
vector<int> v1;
vector<int> v2(v1.begin(),v1.end());
vector<int> v3(10,100);//前面表示个数,后面表示值
vector<int> v4(v3);
}
赋值操作
void test01()
{
vector<int> v1;
for(int i=0;i<10;i++) v1.push_back(i);
vector<int> v2;
v2 = v1;
vector<int>v3;
v3.assgin(v1.begin(),v1.end());
vector<int> v4;
v4.assgin(10,100);
}
容量和大小
void test01()
{
vector<int> v1;
for(int i=0;i<10;i++) v1.push_back(i);
if(v1.empty()) cout<<"v1为空"<<endl;
cout<<"v1的容量"<<v1.capacity()<<endl;
cout<<"v1的大小"<<v1.size()<<endl;
v1.resize(15);
cout<<"v1的大小"<<v1.size()<<endl;//默认以0填充新的位置
}
插入和删除
void test01()
{
vector<int> v1;
for(int i=0;i<10;i++) v1.push_back(i);
v1.pop_back();//删除尾部元素
v1.insert(v1.begin(),100);//第一个参数为迭代器,第二个为数值
v1.erase(v1.begin());//删除迭代器位置元素
v1.clear();
}
note:vector insert方法使用的为迭代器,string为位置
数据存取
vector的数据存取同string类似
互换容器swap
功能为实现两个容器内元素进行互换
代码非常简单 v1.swap(v2);
当重新指定容器大小的时候,可能由于之前使用的容量大造成容量浪费
使用
vector<int> (v1).swap(v1);
可以重新分配容量
预留空间
减少vector在动态容量扩展中的次数
v.reserve(int len); //容器预留len个元素长度,预留位置不初始化,元素不可访问
deque容器
双端数组,可以进行头部的插入和删除操作
为什么deque可以进行双端插入呢?
在于其内部存在一个中控器,存放各个缓冲区的地址,然后缓冲区存放真实数据,这样使得deque看起来像连续的内存空间,但其访问速度要相对vector慢上一些,原因在于其要先找到对应缓冲区的地址,然后再访问数据
构造函数
void test01()
{
deque<int>d1;
deque<int>d2(d1.begin(),d1.end());
deque<int>d3(10,100);
deque<int>d4(d3);
}
deque的其余操作基本同vector一致
deque没有容量的概念
deque可以进行头插,头删和尾插,尾删
其余插入删除操作和vector类似
stack栈式容器
特点
先进后出,只有一个出口,只在顶部进出,因为只有栈顶元素才可以被外界访问到,所以不可以进行遍历,但是可以判断容器是否为空,以及其中元素数目
入栈:push
出栈:pop
举个例子,弹匣,只能从顶端往里面放,顶端弹出,然后每次使用的是最上的一颗子弹
常用接口
void test01()
{
stack<int> s;
s.push(1);
s.push(2);
if(!s.empty())
{
cout<< "栈顶元素:"<<s.top()<<endl;
s.pop();
}
cout<<"栈的大小:"<<s.size()<<endl;
}
queue队列容器
遵循规则:先进后出,存在两个出口,但是出去只能从队首出,进入从队尾进入
只有队首和队尾才可以被外界访问到,因此队列也不允许有遍历行为
数据进入叫入队 push
数据出去叫出队 pop
其方法同stack栈相差不大,这里就不多做介绍了
list链表
功能:将数据进行链式存储
链表是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的
链表由一系列节点组成
包含两个域:分别为存储数据元素的数据域以及下一个结点地址的指针域
STL中给提供的链表是一个双向循环链表
存在两个指针域,一个指向前面的结点,一个指向后面的结点,同时最后一个结点指向第一个结点
链表中的迭代器只会支持前移和后移,属于双向迭代器
构造函数
void test01()
{
list<int> L1;
L1.push_back(10);
L1.push_back(20);
list<int>L2(L1.begin(),L2.begin);
list<int>L3(L2);
list<int>L4(10,1000);
}
list构造方式同其余容器的方式基本一致
赋值和交换
大小操作
插入和删除
这里注意pos代表的是迭代器,同时新增方法remove,此方法是可以移除容器中所有域elem相同的元素
list的反转和排序
bool myCompare(int v1,int v2) { return v1>v2; }
void test01()
{
list<int> l1;
l1.push_back(10);
l1.push_back(20);
l1.push_back(40);
l1.push_back(30);
//反转操作
l1.reverse();
l1.sort();//默认为从小到大
l1.sort(myCompare);
}
note:所有不支持随机访问迭代器的容器,不可以使用标准算法,内部会存在一些算法
set/multiset集合容器
所有元素都会再插入时自动被排序
均属于关联式容器,底层结构是用二叉树实现
set中不允许存在重复的元素,multiset允许容器存在重复的元素
set构造函数提供两种构造方法
默认构造函数:set<T> st;
拷贝构造函数:set(const set &st);
赋值操作:重载等号运算符。
note:插入数据仅有insert方式
使用size()判断容器中元素的数据
empty() 判断容器是否为空
swap(st) 交换两个集合容器
set容器的删除操作
set容器的查找与统计
对于set而言,统计的结果要么是0,要么是1
对组
pair<string,int>p("Tom",20);
p.first//取出第一个数据
p.second//取出第二个数据
pair<string,int>p = make_pair("Tom",20);
改变set容器排序规则
利用仿函数
//set容器排序
class mycompare
{
public:
bool operator()(int v1,int v2)
{ return v1>v2; }
}
void test01()
{
set<int,mycompare> s1;
s1.insert(10);
s1.insert(20);
s1.insert(30);
s1.insert(40);
//指定排序规则,需要在还没有插入数据的时候确定排序规则
}
map元组
map中元素都是键值对
第一个元素为键值,起到一个索引的作用
第二个元素为实值
所有元素回按照元素的键值进行自动排序,底层使用二叉树实现
优点在于可以根据key值快速找到value值
map容器不允许容器存在重复的key元素
构造包括默认构造和拷贝构造
赋值还是重载了等号运算符
void test01()
{
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>(4,40));
//迭代器访问
map<int,int>::iterator it = m.begin();
it -> first;//访问key
it -> second;//访问value
}
查找,统计,插入,删除与set类似,这里不做介绍