【C++提高编程(二)】常用STL容器

本文详细介绍了C++STL中的几种主要容器,包括string的基本概念、构造函数、赋值操作、字符串拼接、查找和替换等;vector的动态扩展、构造函数、赋值操作、容量和大小管理、插入和删除等特性;deque的双端操作和数据存取;stack的栈操作接口;queue的队列操作接口;以及list的链表结构、插入删除操作;最后讨论了set和multiset、map和multimap的关联式容器特性和使用方法。

3 STL常用容器

3.1 string容器

3.1.1 string基本概念

本质:

string是c++风格的字符串,而string本质上是一个类

*string和char 区别:

1. char* 是一个指针(C风格字符串)
2. string是一个类,类内部封装了char*  ,管理这个字符串,是一个char* 型的容器(C++风格字符串)

特点:

string类内封装了很多成员方法

例如:查找find,拷贝copy,删除delete,替换replace,插入insert

string管理char* 所分配的内存,不用担心复制越界和取值越界等,由类内部进行负责。

3.1.2 string构造函数
string();    //创建一个空的字符串 例如: string str;
string(const char* s);  //使用字符串s初始化
string(const string& str); //使用一个string对象初始化另一个string对象
string(int n, char c);   //使用n个字符c初始化
3.1.3 string赋值操作

赋值的函数原型:

string& 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赋给当前字符串
3.1.4 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个字符连接到字符串结尾
3.1.5 string查找和替换

查找:查找指定字符串是否存在,找到字符串后返回查找到的第一个位置,否则返回-1

//此处写出的都是常函数形式,使用此种形式可以防止对值的修改
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第一次出现的位置
//rfind从右往左查找  而find从左往右查找
int rfind(cosnt string& str, int pos = npos) const;//查找str最后一次出现的位置,从pos开始查找
int rfind(cosnt 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);//使用整个字符串str替换从pos开始的n个字符
string& replace(int pos, int n, const char* s);//使用整个字符串s替换从pos开始的n个字符
3.1.6 string字符串比较

主要的意义在于判断两字符串是否相等,判断大小意义不大

比较方式:按照字符的ASCII码进行比较

= 返回 0 > 返回 1 < 返回 -1

int compare(const string &s) const;	//与字符串s进行比较
int compare(const char* s) const;	//与字符串s进行比较
3.1.7 string字符存取

通过这种方式可以对指定位置的字符进行访问,并能完成修改等操作

//1. 通过[]方式获取字符
char& operator[](int n);	
	字符串名[n];		//实际使用时的形式
//2. 通过at方法获取字符
char& at(int n);			
	字符串名.at(n);
3.1.8 string字符串插入和删除
string& insert(int pos, const char* s);		//插入字符串
string& insert(int pos, const string& str);	//插入字符串
string& insert(int pos, int n, char c);		//在指定位置插入n个字符c
string& erase(int pos, int n = npos);		//删除从pos开始的n个字符
3.1.9 string子串

string substr(int pos = 0; int n = npos) const;返回由pos开始的n个字符组成的字符串

3.2 vector容器

3.2.1 vector基本概念

vector数据结构与数组相似,被称为单端数组;与数组的不同之处在于 数组是静态空间,而vector可以动态扩展

动态扩展:并非是在原空间之后续接新空间,而是寻找更大的内存空间,然后将原数据拷贝到新空间,释放原空间

3.2.2 vector构造函数
vector<T> v;		//采用模板实现类实现,默认构造函数
vector(v.begin(), v.end());	//将v[begin(),end()]区间中的元素拷贝给自身
vector(n, elem);	//构造函数将n个elem拷贝给本身
vector(const vector &vec);	//拷贝构造函数
3.2.3 vector赋值操作
vector& operator=(const vector &vec);//重载赋值操作符
assign(begin, end);				//将[begin,end)区间的数据拷贝赋值给本身
assign(n, elem);				//将n个elem拷贝赋值给本身
3.2.4 vector容量和大小
empty();				//判断容器是否为空,空返回1,非空返回0
capacity();				//容器的容量(容器最多可以容纳元素的个数)
size();					//返回容器中元素的个数
resize(int num);		//重新指定容器的长度为num,若容器变长,则以默认值0填充新位置;如果容器变短,末尾超出容器长度的元素会被删除
resize(int num, elem);//重新指定容器的长度为num,若容器变长,则以elem填充新位置;如果容器变短,末尾超出容器长度的元素会被删除
3.2.5 vector插入和删除
push_back(ele);			//尾部插入元素ele
pop_bask();				//删除最后一个元素
insert(const_iterator pos, ele);//迭代器指向位置pos插入元素ele
insert(const_iterator pos, int count, ele);//迭代器指向位置pos插入count个元素ele
erase(const_iterator pos);	//删除迭代器指向元素
erase(sont_iterator start, const_iterator end)//删除迭代器从start到end之间的所有元素
clear();			//删除容器中所有元素
3.2.6 vector数据存取
at(int idx);		//返回索引idx所指的数据
operator[];			//返回索引idx所指的数据
front();			//返回容器中第一个数据元素
back();				//返回容器中最后一个数据元素
3.2.7 vector互换容器

实现两个容器内元素的互换

swap(vec);			//将vec与本身的元素进行互换

巧用swap可以收缩内存空间:在capacity很大时,如果使用resize使得capacity>>size,(这样并不会改变容器的capacity),可以使用下列语句使capacity与size尺寸相同/相近:

vector<int>(v).swap(v);		//vector<int>(v)是一个匿名对象,相当于使用v现在的数据新建了一个匿名对象,然后将其与现有的v进行互换
3.2.8 vector预留空间

减少vector在动态扩展容量时的扩展次数,如果数据量较大,可以在一开始利用reserve预留空间

reserve(int len);	//容器预留len个元素长度,预留位置不进行初始化,元素不可访问

3.3 deque容器

读法:戴克

调用时需要包含deque头文件

3.3.1 deque容器基本概念

双端数组,可以对头端进行插入删除操作

deque和vector的区别:

  • vector对于头部的插入删除效率低,数据量越大,效率越低
  • deque相对而言,对头部的插入删除速度比deque快
  • vector访问元素时的速度会比deque快,这和两者内部的实现有关

deque有个中控器,维护每段缓冲区中的内容,缓冲区用来存放真实数据;中控器维护的是每个缓冲区的地址,使得使用deque时像一片连续的内存空间

deque容器的迭代器也是支持随机访问的

3.3.2 deque构造函数
deque<T> //默认构造
deque(beg, end);//构造函数将[beg, end)区间中的元素拷贝给本身
deque(n, elem);//构造函数将n个elem拷贝给本身
deque(const deque &deq);//拷贝构造函数
3.3.3 deque赋值操作
deque& operator=(const deque &deq);//重载赋值操作符
assign(beg, end);			//将[beg, end)区间内的数据拷贝赋值给本身
assign(n, elem);			//将n个elem拷贝赋值给本身
3.3.4 deque大小操作

注意:deque容器没有容量(capacity)的概念

deque.empty();		//判断容器是否为空
deque.size();		//返回容器中元素的个数
deque.resize(num);	//重新指定容器的长度为num,若容器变长,则以默认值填充新位置;如果容器变短,则末尾超出容器长度的元素被删除
deque.resize(num,elem);//重新指定容器的长度为num,若容器变长,则以elem填充新位置;若容器变短,则末尾超出容器长度的元素被删除
3.3.5 deque插入和删除

两端操作:

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位置的数据,返回下一个数据的位置

插入和删除提供的位置是迭代器!

3.3.6 deque数据存取
at(int idx);	//返回索引idx所指的数据
operator[];		//返回索引idx所指的数据
front();		//返回容器中第一个数据元素
back();			//返回容器中最后一个数据元素
3.3.7 deque排序
sort(iterator beg, iterator end)	//对[beg, end)区间内的元素进行排序,默认为从小到大

对于支持随机访问迭代器的容器,都可以利用sort算法进行排序

3.4 stack容器

3.4.1 stack 栈

stack是一种先进后出(First In Last Out, FILO)的数据结构,只有一个出口

栈中只有栈顶的元素才可以被外界使用,因此栈不允许有遍历行为

栈中进入数据:入栈push 栈中弹出数据:出栈pop

3.4.2 stack常用的对外接口
//构造函数
stack<T> stk;			//stack采用模板类实现,stack对象的默认构造形式
stack(const stack& stk);//拷贝构造函数
//赋值操作
stack& operator=(const stack& stk);//重载赋值操作符
//数据存取
push(elem);			//向栈顶添加元素
pop();				//从栈顶移除第一个元素
top();				//返回栈顶元素
//大小操作
empty();			//判断堆栈是否为空
size();				//返回栈的大小

3.5 queue容器

3.5.1 queue 队列

Queue是一种先进先出(First In First Out, FIFO)的数据结构,有两个出口

队列容器允许从一端新增数据,从另一端移除数据

队列中只有队头和队尾才可以被外界使用,因此不允许有遍历行为

队列中进入数据:入队push 队列中弹出数据:出队pop

3.5.2 queue常用接口
//构造函数
queue<T> que;			//queue采用模板类实现,queue对象的默认构造形式
queue(const queue& que);//拷贝构造函数
//赋值操作
queue& operator=(const queue& que);//重载赋值操作符
//数据存取
push(elem);				//往队尾添加一个元素
pop();					//从队头移除一个元素
back();					//返回最后一个元素
front();				//返回第一个元素
//大小操作
empty();				//判断队列是否为空
size();					//返回队列的大小

3.6 list容器

3.6.1 list 链表

链表将数据进行链式存储。链表(list)是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的。

链表由一系列结点组成;而结点包括两部分,一部分是存储数据元素的数据域,另一个是存储下一个节点地址的指针域。

链表优点:

  • 采用动态存储分配,不会造成内存浪费和溢出
  • 链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素

链表缺点:容器遍历速度没有数组快(无法实现随机访问);占用空间比数组大

STL中的链表是一个双向循环链表

由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器支支持前移和后移,属于双向迭代器

list的一个重要的性质是,插入和删除操作都不会造成原有list迭代器的失效,这在vector是不成立的

3.6.2 list构造函数
list<T> lst;			//list采用模板类实现,对象的默认构造形式
list(beg, end);			//构造函数将[beg, end)区间中的元素拷贝给自身
list(n, elem);			//构造函数将n个elem拷贝给本身
list(cosnt list &list);//拷贝构造函数
3.6.3 list赋值和交换
assign(beg, end);	//将[beg, end)中的数据拷贝赋值给自身
assign(n, elem);	//将n个elem拷贝赋值给自身
list &operator=(const list &list);//重载赋值操作符
swap(lst);			//将lst与本身的元素互换
3.6.4 list大小操作
size();			//返回容器中元素的个数
empty();		//判断容器是否为空
resize(num);	//重新指定容器的长度为num,如果容器变长,则以默认值填充新位置;容器变短则超出容器长度的元素会被删除
resize(num, elem);//重新指定容器的长度为num,如果容器变长,则以elem填充新位置;容器变短则超出容器长度的元素会被删除
3.6.5 list插入和删除
push_back(elem);		//在容器尾部加入一个元素
pop_back();				//删除容器中最后一个元素
push_front(elem);		//在容器开头插入一个元素
pop_front();			//从容器开头移除一个元素
insert(pos, elem);		//在pos位置插入元素的拷贝并返回新数据的位置
insert(pos, n, elem);	//在pos位置插入n个elem数据,无返回值
insert(pos, beg, end);	//在pos位置插入[pos, end)区间的数据,无返回值
clear();				//移除容器中所有的数据
erase(beg, end);		//删除[beg, end)区间的数据,并返回下一数据的位置
erase(pos);				//删除pos位置的数据,返回下一个数据的位置
remove(elem);			//删除容器中所有与elem值匹配的元素
3.6.6 list数据存取

list不支持随机访问,即不支持使用 []at(idx) 的形式访问元素,只可以使用 front(); 返回第一个元素、以及 back();返回最后一个元素

3.6.7 list反转排序
reverse();		//反转链表
sort();			//链表升序排序

所有不支持随机访问迭代器的容器,不可以使用标准算法,只可以使用内部提供的算法;此处需要调用的是 list.sort();,而并非前面所用的 sort(beg, end);

list.sort();支持传入参数,可以传入自定义大小比较的函数名来进行降序排序

bool myCompare(int v1, int v2){
    return v1 > v2;	//让第一个数大于第二个数,达成降序的效果
}
list1.sort(myCompare);

3.7 set/multiset 容器

3.7.1 set基本概念

所有元素会在插入时被自动排序。

set/multiset属于关联式容器,底层结构使用二叉树来实现。两者间的不同在于,set不允许容器中由重复的元素,但multiset允许容器中有重复的元素。

3.7.2 set构造和赋值
set<T> st;		//默认构造函数
set(const set &st);//拷贝构造函数
set& operator=(const set& st);//重载赋值操作符
3.7.3 set大小和交换
size();		//返回容器中元素的数目
empty();	//判断容器是否为空
swap(st);	//交换两个集合容器
3.7.4 set插入和删除
insert(elem);		//在容器中插入元素
clear();			//清除所有元素
erase(pos);			//删除pos迭代器所指的元素,返回下一个元素的迭代器
erase(beg, end);	//删除区间[beg, end)的所有元素,返回下一个元素的迭代器
erase(elem):		//删除容器中值为elem的元素
3.7.5 set查找和统计
find(key);			//查找key是否存在,若存在,返回该键元素的迭代器;若不存在返回set.end()
count(key);			//统计key元素的个数

find()返回的结果是迭代器

count()对于set来说返回的结果是0或1

3.7.6 set和multiset的区别

set插入数据会返回一个表示插入是否成功的pair对组,不允许重复数据插入;

multiset插入数据直接返回迭代器,不会对重复数据进行检查

3.7.7 pair对组创建

对于成对出现的数据,利用对组可以返回两个数据

pair<type, type> p(value1, value2);
pair<type, type> p = make_pair(value1, value2);

访问对组中的元素:

p.first;		//返回对组中的第一个元素
p.second;		//返回对组中第二个元素
3.7.8 set容器排序

set默认排序规则是从小到大,利用仿函数可以改变排序规则

//内置数据类型,可以在建立set时指定排序规则
class MyCompare{
public:
    bool operator()(int v1, int v2){
        return v1 > v2;
    }
};
set<int, MyCompare>s2;	//s2的排序规则为从大到小降序

对于自定义数据类型,必须要使用仿函数指定排序规则才可以插入数据

set<Person, comparePerson>s;

3.8 map/multimap容器

3.8.1 map基本概念

map中所有元素都是pair,pair中第一个元素为key(键值),起到索引的作用,第二个元素为value(实值);所有元素都会根据元素的键值自动排序。

本质:map/multimap属于关联式容器,底层结构使用二叉树实现

优点:可以根据key值快速找到value值

map和multimap的区别:map不允许容器中有重复key值的元素;而multimap允许容器中有重复key值的元素

3.8.2 map构造和赋值
map<T1, T2> mp;		//map默认构造函数
map(const map& map);//map拷贝构造函数
map& operator=(const map& mp);//重载赋值操作符

map中所有元素都成对出现,因此插入数据时应使用对组pair

3.8.3 map大小和交换
size();				//返回容器中元素的数目
empty();			//判断容器是否为空
swap(map);			//交换两个map容器
3.8.4 map插入和删除
//map四种插入方式
m.insert(pair<T1, T2>(key1, value2));	
m.insert(make_pair(key1, value2));
m.insert(pair<T1, T2>::value_type(key1, value2));
m[key1] = value1;//不建议使用[]插入,多用于使用key访问value
//删除操作
clear();			//清除所有元素
erase(pos);			//删除pos迭代器所指的元素,返回下一个元素的迭代器
erase(beg, end);	//删除区间[beg, end)的所有元素,返回下一个元素的迭代器
erase(key);			//删除容器中键值为key的元素,若不存在该键值则不删除
3.8.5 map查找和统计
find(key);//查找key是否存在,存在则返回该键元素的迭代器,不存在返回map.end()
count(key);//统计key的元素个数,对map而言值为0或1
3.8.6 map容器排序

map的默认排序顺序是从小到大升序排序,利用仿函数可以改变排序规则

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值