STL初识
STL:标准模板库
建立了一套数据结构和算法的标准,包含容器、算法、迭代器
组件
STL大体分为六大组件,分别是:容器、算法、迭代器、仿函数、适配器(配接器)、空间配置器
- 容器:各种数据结构,如vector、 list、 deque、 set、 map等,用来存放数据。
- 序例式容器:强调值的排序,序例式容器中的每个元素均有固定的位置。
- 关联式容器:二叉树结构,各元素之间没有严格的物理上的顺序关系
- 算法:各种常用的算法,如sort、 find、 copy、 for__each等
- 质变算法:是指运算过程中会更改区间内的元素的内容。例如拷贝工替换,删除等等
- 非质变算法:是指运算过程中不会更改区间内的元素内容,例如查找、计数、遍历、寻找极值等等
- 迭代器:扮演了容器与算法之间的胶合剂。提供一种方法,使之能够依序寻访某个容器所含的各个元素,而又无需暴露该容器的内部表示方式。每个容器都有自己专属的迭代器,迭代器使用非常类似于指针,初学阶段我们可以先理解迭代器为指针
- 双向送代器
- 随机访问迭代器
- 函数:行为类似函数,可作为算法的某种策略。
- 适配器: - 种用来修饰容器或者仿函数或迭代器接口的东西。
- 空间配置器:负责空间的配置与管理。
String容器
string是一个类,维护了一个char*的容器,自动管理char*内存,不用担心越界问题。
构造函数
string(); //创建空串 string s1;
string(const char* s); //用字符串初始化 string s1("hello world")
string(const string& str);//拷贝构造,用一个stringg对象初始化另一个 string s2(s1);
string(int n,char c); //用n个c初始化 string(3,'c');
赋值操作
//运算符重载
string& operator=(const char*s);//char*类型学符串 赋值给当前的学符串 str1="hello world"
string& operator=(const string &s);//把字符串s赋给当前的字符串 str2=str1
string& operator=(char c);//字符赋值给当前的字符串 str2='c'
//函数方式
string& assign(const char *s)://把字符串s赋给当前的字符串 str1.assign("hell oworld")
string& assign(const char *s, int n)://把字符串s的前n个字符赋给当前的字符串 str1.assign("hell oworld",3)
string& assign(const string &s);//把字符串s赋给当前字符串 str2.assign(str1)
string& assign(int n, char c);//用n个字符c赋给当前字符串 str1.assign('c',6)
拼接操作
//重载
str1+="123";
str1+='c';
str2+=str1;
//成员函数
str1.append("123");
str1.append("123",2);//前两个追加到str1
str1.append('c',3);
str1.append(str2);
查找和替换
//查找第一次位置 返回位置下标 找不到返回-1
int find(const string& str, int pos =0) const;//查找str第一次出现位置,从pos开始查找 str1.find(str2,0)
int find(const char* s, int pos =0 ) const;//查找s第一次出现位置,从pos开始查找 str1.find("123",0)
int find(const char* s, int pos, int n) const;//从pos位置查找s的前n个字符第一次位置 str1.find("1233",0,2)
int find(const char c, int pos = 0) const;//查找字符c第一次出现位置 str1.find('c',0)
//查找最后一次位置
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 = ) const;//查找字符c最后一次出现位置
//替换
string& replace(int pos, int n, const string& str);//替换从pos开始n个字符为字符串str str1=str1.replace(0,3,str2)
string& replace(int pos, int n,const char* s);//替换从pos开始的n个字符为字符串s str1=str1.replace(0,3,str1)
比较
比较方式:按照ASCII码进行比较,挨个字符按顺序相比,直到第一个不一致的值
-
=返回 0
-
>返回 1
-
<返回 -1
int compare(const string &s) const; //str1.compare(str1)
int compare(const char *s) const; //str1.compare("123")
单个字符存取访问
使用[]或at成员函数
string str = "123";
for(int i = 0;i<str.size();i++){
cout<<str[i]<<endl;
}
for(int i = 0;i<str.size();i++){
cout<<str.at(i)<<endl;
}
str[0] = '8';
str.at(0) = '8';
插入删除
pos起始的(包含pos)字符串往后挪
string& insert(int pos, const char* s);//插入字符串 str.insert(0,"123")
string& insert(int pos, const string& str); //插入字符串 str1.insert(0,str2)
string& insert(int pos, int n, char c);//在指定位置插入n个字符c str.insert(0,,3,'1')
string& erase(int pos, int n = npos);//删除从Pos开始的n个字符 str.erase(0,3)
子串获取
string substr(int pos = 0,int n = npos) const; //返回由pos开始的n个字符组成的字符串 str.substr(0,3)
vector容器
单端数组,可以动态扩展(申请新空间,释放旧空间,和栈不同的是,可以访问里面的元素,而栈只能访问栈顶)
构造函数、iterator遍历
vector<T> v;//采用模板实现类实现,默认构造函数
vector(v.begin(),v.end());//将v[begin(),end0)区间中的元素拷贝给本身
vector(int n, elem);//构造函数将n个elem拷贝给本身
vector(const vector &vec);//拷贝构造函数。
void printitem(vector<int>&v){
for(vector<int>::iterator it=v.begin();it!=v.end();it++){
cout<<*it<<endl;
}
}
void test(){
vector<int>v1;
printitem(v1);
vector<int>v2(v1.begin(),v1.end());
vector<int>v3(v2);
vector<int>v3(10,100);
}
赋值
vector& operator=(const vector &vec); //重载等号操作符 vector<int>v1=v2
assign(beg,end);//将[beg, end)区间中的数据拷贝赋值给本身. v2.assign(v1.begin(),v1.end())
assign(n,elem)//将n个elem拷贝赋值给本身. v2.assign(3,3)
容量和大小
capacity>size
empty();//判断容器是否为空
capacity();//容器的容量
size();//返回容器中元素的个数
resize(int num);//重新指定容器的长度为num比容器大,则以默认值0填满容器.
//如果num比容器小,则末尾超出容器长度的元素被删除。
resize(int num, elem);//重新指定容器的长度为num,若容器变长,则以elem值填充新位置
//如果容器变短,则末尾超出容器长度的元素被删除
插入和删除
push_back(ele);//尾部插入元素ele 入栈
pop_back();//删除最后一个元素 出栈
insert(const iterator pos, ele);//迭代器指向位置pos插入元素 v1.insert(v1.begin(),10) 在头插入10
eleinsert(const_iterator pos,int count,ele);//迭代器指向位置pos插入count个元素 v1.insert(v1.begin(),10,10)
eleerase(const iterator pos);//删除迭代器指向的元素 v1.insert(v1.begin())
erase(const_iterator start,const iterator end); //删除迭代器从start到end之间的元素
clear();//删除容器中所有元素
数据存取和访问遍历
at(int idx);//返回索引idx所指的数据
operator[];//返回索引idx所指的数据
front();//返回容器中第一个数据元素
back();//返回容器中最后一个数据元素
void printitem(vector<int>&v){ //若const vector<int>&v为参数,则下面迭代器也要改成const迭代器,且不能修改内容了
//方式一
for(vector<int>::iterator it=v.begin();it!=v.end();it++){ //vector<int>::const_iterator it=v.begin()
cout<<*it<<endl;
}
//方式二
for(int i = 0;i<v1.size();i++){
cout<<v1.at(i)<<endl;
}
//方式三
for(int i = 0;i<v1.size();i++){
cout<<v1[i]<<endl;
}
}
容器互换
swap(const vector &vec)
巧用swap可以收缩内存空间,容量大的容器里面放的元素较少的时候,可以收缩内存
vector<int>(v).swap(v);
vector(v)是匿名对象 相当于用拷贝构造创建了一个新的对象,元素等同于v但是容量少
随后调用.swap将v和匿名对象互换来达到收缩内存空间的目的。
预留空间
reserve(int len)
预留len空间的长度,多余空间不初始化,不可访问
避免重新分配的内存导致系统消耗
deque容器
双端数组,双端数组,可以对头部插入,插入效率比vector快
deque内部有一个中控器,使得deque像一片连续空间,类似邻接表/多级页表。
构造函数
deque<T> d;//采用模板实现类实现,默认构造函数
deque(d.begin(),d.end());//将d[begin(),end0)区间中的元素拷贝给本身
deque(int n, elem);//构造函数将n个elem拷贝给本身
deque(const deque &deq);//拷贝构造函数。
赋值、大小、数据存取和访问遍历操作
类似vector
插入删除
//插入操作
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位置的数据,返回下一个数据的位置
排序操作
sort(iterator beg,iterator end)
对beg和end之间进行排序,要引入algorithm.h头文件,默认从小到大
sort(d.begin(),d.end())
对于迭代器支持随机访问的容器,都支持sort
stack容器
与vector不容,stack不能遍历
常用接口
//构造函数:
stack<T> stk;//stack采用模板类实现,stack对象的默认构造形式
stack(const stack &stk);//拷贝构造函数
//赋值操作:
stack& operator=(const stack &stk);//重载等号操作符
//数据存取:
push(elem);//向栈顶添加元素
pop();//从栈顶移除第一个元素
top();//返回栈顶元素
//大小操作:
empty() ;//判断堆栈是否为空
size();//返回栈的大小
queue容器
不能遍历,先进先出
常用操作
//构造函数:
queue<T> que;//queue采用模板类实现,queue对象的默认构造形式
queue( const queue &que);//拷贝构造函数
//赋值操作:
queue& operator= (const queue &que);//重载等号操作符
//数据存取:
push(elem);//往队尾添加元素
pop();//从队头移除第一个元素
back();//返回最后一个元素
front();//返回第一个元素
//大小操作:
empty();//判断堆栈是否为空
size();//返回栈的大小
list容器
链表
- 优点
- 非连续存储,双向循环链表
- 插入删除时间复杂度较小
- 缺点
- 随机访问代价大
迭代器只支持前后移,是双向迭代器
List有一个重要性质:插入、删除都不会造成原有list迭代器失效,vector则不成立。(在vector中,如果插满了需要重新找一个内存空间存放,那么原有内存的迭代器就会失效)
构造函数、赋值、互换、大小
与vector相同
插入删除、存取
双向迭代器不能随机访问,不能类似vector进行at操作、[]随机访问
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值匹配的元素
front(); //返回第一个元素
back(); //返回最后一个元素
反转和排序、仿函数初识
reverse()
反转
sort()
排序:默认从小到大
仿函数进行从大到小排序
bool myCompare(int v1,int v2){ //myCompare(Person &p1,Person &v2)
//降序 第一个数>第二个数
return v1>v2;
}
List<int>l1;
l1.sort(myCompare);
set/multiset容器
所有元素都会在插入时自动被排序
关联式容器,结构是二叉树实现。
set/multiset区别
- set不允许重复元素,插入数据同时会返回插入结果,表示插入是否成功(返回pair类型)
pair<set<int>::iterator,bool> ret = s.insert(num)
,ret.second
访问插入结果 - multiset允许重复元素
构造和赋值
//构造:
set<T> st;//默认构造函数:
set(constet &st);//拷贝构造函数
//赋值:
set& operator=(const set &st);//重载等号操作符
大小和交换
不能进行resize的操作,因为会用相同元素填充,而set不允许重复元素。
size();//返回容器中元素的数目
empty( );//判断容器是否为空
swap(st);//交换两个集合容器
插入和删除
insert(elem);//在容器中插入元素。
clear();//清除所有元素
erase(pos);//删除pos迭代器所指的元素,返回下一个元素的迭代器
erase(beg, end);//删除区间[beg,end)的所有元素,返回下一个元素的迭代器
erase(elem);//删除容器中值为elem的元素
查找和统计
find(key)//查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end()
count(key); //统计key的元素个数
修改插入时的排序规则
要创建一个mycompare的类
class myCompare{ //myCompare(Person &p1,Person &v2)
//降序 第一个数>第二个数
public:
bool operator()(int v1,int v2){ //重载运算符() (const Person &p1,const Person &p2)
return v1>v2;
}
}
Set<int,mycompare>s2;
l1.insort(myCompare);
pair对组
//创建
pair<type, type> p( value1, value2 );
pair<type, type> p = make_pair( value1, value2 );
map/multimap容器
简介
-
map中所有元素都是pair
-
pair中第一个元素为key (键值) 起到索引作用,第二个元素为value (实值)
-
所有元素都会根据元素的键值自动排序
本质
map/multimap属于关联式容器,底层结构是用二叉树实现。
优点
可以根据key值快速找到value值map和multimap。
区别
- map不允许容器中有重复key值元素
- multimap允许容器中有重复key值元素
构造和赋值
//构造:
map<T1,T2> mp;//map默认构造函数
map(const map &mp);//拷贝构造函数
//赋值:
map& operator=(const map &mp);//重载等号操作符
大小和交换
size/swap/empty用法和其他相同
插入和删除
注意 插入的elem一定要是元组
insert(elem);//在容器中插入元素。 m.insert(pair<int,int>(1,10)) 或 m.insert(make_pair(1,10))
clear();//清除所有元素
erase(pos);//删除pos迭代器所指的元素,返回下一个元素的迭代器
erase(beg, end);//删除区间[beg,end)的所有元素,返回下一个元素的迭代器
erase(key);//删除容器中值为key的元素.
查找和统计
find(key); //存在返回迭代器,不存在返回set.end()
count(key);
修改排序规则
class myCompare{ //myCompare(Person &p1,Person &v2)
//降序 第一个数>第二个数
public:
bool operator()(int v1,int v2){ //重载运算符() (const Person &p1,const Person &p2)
return v1>v2;
}
}
map<int,int,mycompare> m