c++STL各个容器使用介绍


前言

  这人呀,年纪一到脑子就不够用了,每次使用STL中的一些函数时,大概有些映像,但是就是不能具体想出函数名称是啥或者具体参数是啥,百度大法虽然好但是着实影响效率,今天我就整理一下STL中的常用容器和常用函数用法,一篇博文基本解决STL的常用用法。

一、容器

1.序列式容器

1.1 字符串(string)

  字符串包括字符操作再leetcode刷题中经常遇到,是处理一些问题的基础,需要重点掌握。
string初始化:https://blog.csdn.net/VariatioZbw/article/details/116592225

1.1.1 将string转换为char*

方法1:使用c_str()方法
  代码如下:

#include <string>
#include <iostream>
#include <stdio.h>
 
using namespace std;
 
int main()
{
    string strOutput = "Hello World";
 
    cout << "[cout] strOutput is: " << strOutput << endl;
 
    // string 转换为 char*
    const char* pszOutput = strOutput.c_str();
    
    printf("[printf] strOutput is: %s\n", pszOutput);
 
    return 0;
}

编译并执行上述代码,结果如下:
在这里插入图片描述
上述代码执行结果说明:

  • cout 可直接输出 string 类的对象的内容;
  • 使用 c_str() 方法转换 string 类型到 char* 类型时,需要为char*添加 const 关键字
  • printf() 函数不能直接打印 string 类的对象的内容,可以通过将 string 转换为 char* 类型,再使用 printf() 函数打印。
    方法2:使用data()方法

data()方法与c_str()方法相似,都返回 const char* 类型。两者区别和联系如下:

  • 在C++98版本中,c_str()返回 const char* 类型,返回的字符串会以空字符(null character)结尾;
  • 在C++98版本中,data()返回 const char* 类型,返回的字符串不以空字符(null character)结尾;
  • 在C++11版本中,c_str()与data()用法相同(Both string::data and string::c_str are synonyms and return the same value.)

注意:使用atoi() 和 atof()时需要先将string转化为const char*格式,即利用c_str()先转为const char *,然后再使用atoi()将字符串转化为int型数,或使用atof转化为float型数

1.1.2 常见函数
s.size()  // 求长度
s.empty()  // 判断是否为空

s.insert(int index, string str) // 在s[4]的位置插入str
// 举例说明
string s = "I am";
s.insert(4," good");  // 此时s为 I am good

s.substr(int pos,int length) // 从位置pose处开始,截取长度为length的子串
1.1.3 string中的find操作

find
注:学会find操作即可
注意:学会find操作就可以了,其他的不用理会,int find(char c,int pos = 0) const : 默认是从0位置开始找,没有找到返回npos这个关键字,其他的方法不用了解,用不到!!!

// string 中find方法
//从pos开始查找字符c在当前字符串的位置
int find(char c, int pos = 0) const;

//从pos开始查找字符串s在当前串中的位置
int find(const char *s, int pos = 0) const;

//从pos开始查找字符串s中前n个字符在当前串中的位置
int find(const char *s, int pos, int n) const;

//从pos开始查找字符串s在当前串中的位置
int find(const string &s, int pos = 0) const;

//以上查找成功时返回所在位置,失败返回string::npos的值

rfind

// string中的rfind函数
//从pos开始从后向前查找字符c在当前串中的位置
int rfind(char c, int pos = npos) const;
int rfind(const char *s, int pos = npos) const;
int rfind(const char *s, int pos, int n = npos) const;
int rfind(const string &s,int pos = npos) const;

//从pos开始从后向前查找字符串s中前n个字符组成的字符串在当前串中的位置,成功返回所在位置,失败时返回string::npos的值

还有一些其他的查找功能,详见https://blog.csdn.net/u014203453/article/details/77740423

1.1.4 将char*、char[]转化为string

将 char*、char[] 转换为 string 类型时,直接进行赋值操作,将 char*、char[] 的变量赋值给 string 对象即可。

说明:这里所说的“赋值”操作,实际上是将 char*、char[] 定义的字符串的首地址赋值给 string 对象了。

示例代码(stringtochar.cpp)如下:

#include <string>
#include <iostream>
 
using namespace std;
 
int main()
{
    const char* pszName = "liitdar";
    char pszCamp[] = "alliance";
 
    string strName;
    string strCamp;
 
    strName = pszName;
    strCamp = pszCamp;
 
    cout << "strName is: " << strName << endl;
    cout << "strCamp is: " << strCamp << endl;
 
    return 0;
}

在这里插入图片描述

1.1.4.2 单独的一个字符串与string类型的转化
1.
char c = 'a';
string str = {c};

2.
char c = 'a';
string str;
str.push_back(c);

不存在 字符类型 char到string类型的强制类型转化,即 string©会报错。

1.1.5 char型与整型的相互转化

首先需要注意的一点是将char型转化为整型不能直接通过int()强制类型转化,否则的话会转化为对应ascii码值,如下所示:

int main()
{
	// char 转为 int
	char a_c = '0';
	int a = int(a_c);
	int b = a_c - '0';
	cout << a << endl;
	cout << b << endl;

	// int 转为 char
	char b_c = b + '0';
	cout << b_c << endl;

	return 0;

}

结果如下:
在这里插入图片描述

可以知道 a_c - ‘0’ 才是正确的。

1.2 vector

1.2.1 vector常见函数

注意:erase的用法需要注意,里面的参数必须是迭代器,如arr.erase(arr.begin()+i),或者先用auto iter = find(arr.begin(),arr.end(),num) ,然后删除:arr.erase(iter)

int size() : 返回容器对象中元素的个数
bool empty(): 判断容器对象是否为空

begin():返回指向容器中第一个元素的迭代器。

end():返回指向容器中最后一个元素后面的位置的迭代器。

rbegin():返回指向容器中最后一个元素的反向迭代器。

rend():返回指向容器中第一个元素前面的位置的反向迭代器。

erase(iterator loc): 删除loc位置的元素(https://img2018.cnblogs.com/blog/1169804/201903/1169804-20190310230711138-1115905688.png)
erase(iterator first,iterator last): 删除[first,last)这一段
***需要注意,在进行单个元素删除后,传入的迭代器指向不变,仍然指
向被删除元素的位置,而被删除元素之后的所有元素都向前移动一位,也
就是该迭代器实际上是指向了原来被删除元素的下一个元素***

clear():从容器中删除所有元素。

front():返回容器中第一个元素的引用。

back():返回容器中最后一个元素的引用。

push_back():在容器末尾增加新元素。

pop_back():删除容器末尾的元素。

insert(iterator loc ,size_type num):指定位置loc前面插入元素

// c++ 11新特性
emplace_back(): 对标push_back()
emplace() : 对标insert()
find(vec.begin(),vec.end(),N);  //在vec中查找N,返回迭代器
// 如果返回的是 vec.end() 说明没有找到,即数组中不存在这个数
// 此外如果需要使用二分查找则必须是已经排序的数组

1.3 list

  list也是顺序容器的一种,知识list底层是一个双向链表,使用list必须包含头文件list。双向链表的每个元素中都有一个指针指向后一个元素,也有一个指针指向前一个元素,如下图所示。
在这里插入图片描述
  当然,list的用法和vector很类似,也拥有顺序容器中的常用方法,需要注意的是**list不支持使用下标随机存取元素。
在 list 容器中,在已经定位到要增删元素的位置的情况下,增删元素能在常数时间内完成。如下图所示,在 ai 和 ai+1 之间插入一个元素,只需要修改 ai 和 ai+1 中的指针即可
在这里插入图片描述

1.3.1 list的相关函数
#include <list>

// 1.头尾的添加移除操作
list.push_back(elem); //在容器尾部加入一个元素
list.pop_back(); //删除容器中最后一个元素
list.push_front(elem); //在容器开头插入一个元素
list.pop_front(); //从容器开头移除第一个元素

// 2.数据存取
list.front(); //返回第一个元素。
list.back(); //返回最后一个元素。

// 3.与迭代器相关
list.begin(); //返回容器中第一个元素的迭代器。
list.end(); //返回容器中最后一个元素之后的迭代器。
list.rbegin(); //返回容器中倒数第一个元素的迭代器。
list.rend(); //返回容器中倒数最后一个元素的后面的迭代器。

// 4.带参构造(和vector类似)
list(beg,end); //构造函数将[beg, end)区间中的元素拷贝给本身。注意该区间是左闭右开的区间。
list(n,elem); //构造函数将n个elem拷贝给本身。
list(const list &lst); //拷贝构造函数

// 5.大小相关(和vector类似)
list.size(); //返回容器中元素的个数
list.empty(); //判断容器是否为空
list.resize(num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
list.resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。

// 6.插入元素(注意是迭代器)
list.insert(pos,elem); //在pos位置插入一个elem元素的拷贝,返回新数据的位置。
list.insert(pos,n,elem); //在pos位置插入n个elem数据,无返回值。
list.insert(pos,beg,end); //在pos位置插入[beg,end)区间的数据,无返回值。

// 7.删除元素
list.clear(); //移除容器的所有数据
list.erase(beg,end); //删除[beg,end)区间的数据,返回下一个数据的位置。
list.erase(pos); //删除pos位置的数据,返回下一个数据的位置。
lst.remove(elem); //删除容器中所有与elem值匹配的元素。

// 8.反序排列
lst.reverse(); //反转链表

// 9.赋值操作
赋值操作
list.assign(beg,end); //将[beg, end)区间中的数据拷贝赋值给本身。注意该区间是左闭右开的区间。
list.assign(n,elem); //将n个elem拷贝赋值给本身。
list& operator=(const list &lst); //重载等号操作符
list.swap(lst); //将lst与本身的元素互换。

// 10.排序
sort(): // 排序,注意和vector的区别
// STL中的算法sort可以对vector和deque进行排序,它需要随机访问迭代器的支持,因为list不支持随机访问迭代器,所以不能用sort对list进行排序,因此list容器引入了sort成员函数以完成排序,

其他成员函数:
在这里插入图片描述

1.3.2 list的元素访问

  不同于之前学过的 STL 容器,访问 list 容器中存储元素的方式很有限,即要么使用 front() 和 back() 成员函数,要么使用 list 容器迭代器。

list 容器不支持随机访问,未提供下标操作符 [] 和 at() 成员函数,也没有提供 data() 成员函数。

通过 front() 和 back() 成员函数,可以分别获得 list 容器中第一个元素和最后一个元素的引用形式。举个例子:

#include <iostream>
#include <list>
using namespace std;

int main()
{
    std::list<int> mylist{ 1,2,3,4 };
    int &first = mylist.front();
    int &last = mylist.back();
    cout << first << " " << last << endl;
    first = 10;
    last = 20;
    cout << mylist.front() << " " << mylist.back() << endl;
    return 0;
}

在这里插入图片描述

#include <iostream>
#include <list>
using namespace std;
int main()
{
    const std::list<int> mylist{1,2,3,4,5};
    auto it = mylist.begin();
    cout << *it << " ";
    ++it;
    while (it!=mylist.end())
    {
        cout << *it << " ";
        ++it;  
    }
    return 0;
}

在这里插入图片描述

1.4 deque

deque是双端队列,deque容器为一个给定类型的元素进行线性处理,像向量一样,它能够快速地随机访问任一个元素,并且能够高效地插入和删除容器的尾部元素。但它又与vector不同,deque支持高效插入和删除容器的头部元素,因此也叫做双端队列。deque类常用的函数如下。
deque():创建一个空deque

deque(int nSize):创建一个deque,元素个数为nSize

deque(int nSize,const T& t):创建一个deque,元素个数为nSize,且值均为t

deque(const deque &):复制构造函数

增加数

void push_front(const T& x):双端队列头部增加一个元素X

void push_back(const T& x):双端队列尾部增加一个元素x

iterator insert(iterator it,const T& x):双端队列中某一元素前增加一个元素x

void insert(iterator it,int n,const T& x):双端队列中某一元素前增加n个相同的元素x

void insert(iterator it,const_iterator first,const_iterator last):双端队列中某一元素前插入另一个相同类型向量的[first,last)间的数据

删除数

Iterator erase(iterator it):删除双端队列中的某一个元素

Iterator erase(iterator first,iterator last):删除双端队列中[first,last)中的元素

void pop_front():删除双端队列中最前一个元素

void pop_back():删除双端队列中最后一个元素

void clear():清空双端队列中所有元素

reference at(int pos):返回pos位置元素的引用

reference front():返回首元素的引用

reference back():返回尾元素的引用

iterator begin():返回向量头指针,指向第一个元素

iterator end():返回指向向量中最后一个元素下一个元素的指针(不包含在向量中)

reverse_iterator rbegin():反向迭代器,指向最后一个元素

reverse_iterator rend():反向迭代器,指向第一个元素的前一个元素

1.5 stack

很简单,没什么好说的,参考链接: https://blog.csdn.net/summer00072/article/details/80753821

C++ Stack(堆栈) 是一个容器类的改编,为程序员提供了堆栈的全部功能,——也就是说实现了一个先进后出(FILO)的数据结构。

c++ stl栈stack的头文件为: 

#include <stack> 

c++ stl栈stack的成员函数介绍

操作 比较和分配堆栈

empty() 堆栈为空则返回真

pop() 移除栈顶元素

push() 在栈顶增加元素

size() 返回栈中元素数目

top() 返回栈顶元素

1.6 queue

也很简单,

queue入队,如例:q.push(x); 将x 接到队列的末端。

queue出队,如例:q.pop(); 弹出队列的第一个元素,注意,并不会返回被弹出元素的值。

访问queue队首元素,如例:q.front(),即最早被压入队列的元素。// 不是用的top,而是front

访问queue队尾元素,如例:q.back(),即最后被压入队列的元素。

判断queue队列空,如例:q.empty(),当队列空时,返回true。

访问队列中的元素个数,如例:q.size()

1.7 heap

1.heap概述

  heap处于头文件#include<algorithm>中,STL在<algorithm.h>中实现了对存储在数组或者vector中(是的,没错,堆的底层是vector,堆是基于vector的特殊的数据结构)的元素进行堆操作的函数,包括make_heap,pop_heap,push_heap,sort_heap。
  默认情况下是max-heap,该大顶堆实际上是以一个vector表现的完全二叉树。

2.heap函数介绍

算了,队自己写吧,别看这些了。

// heap操作得四个函数
make_heap(_First,_Last,_Comp) : 建立堆(要么大顶堆,要么就是小顶堆)
push_heap(_First,_Last,_Comp) : 在堆中添加元素
pop_heap(_First,_Last,_Comp) : 在堆中删除元素
sort_heap(_First,_Last,_Comp) : 堆排序
相关参数介绍:
 _First , _Last : 可以随机访问的迭代器/指针
 _Comp : 比较函数(仿函数),其规则是:如果函数的第一个参数小于第二个参数应返回true,否则返回false,默认为less
以数据类型为int为例:若使用大顶堆,则_Comp为 less<int>()  , 小顶堆则为 greater<int>()

下面举例说明:
建立堆:

vector<int> min= {10,30,22,6,15,9};
//建立小顶堆
make_heap(min.begin(), min.end(), greater<int>()); //此时min中数据顺序如下:6 10 9 30 15 22

// 插入元素
min.push_back(20);
push_heap(min.begin(),min.end(), greater<int>());//该算法前提:必须在堆的条件下
// 此时 min:6 10 9 30 15 22 20 仍为小顶堆

// 删除堆顶元素
pop_heap(min.begin(),min.end(),greater<int>());
//此时min:9 10 20 30 15 22 6  不为小顶堆 这个pop_heap操作后,实际上是把堆顶元素放到了末尾
min.pop_back();  // 这才彻底在底层vector数据容器中删除堆顶元素
// 此时 min:9 10 20 30 15 22  仍为小顶堆

// 堆排序,保持greater,小顶堆,得到的是降序
sort_heap(min.begin(),min.end(), greater<int>());//试了用less,结果杂乱无章
//min:30 22 20 15 10 9 注意结果是降序的哦!!!其实是调用了很多次pop_heap(...,greater..),每一次都把小顶堆堆顶的元素往末尾放,没放一次end迭代器减1

// 建立大顶堆的例子类时,将greater<int>()换成less<int>()即可

1.7 priority_queue

常用函数

在这里插入图片描述
  需要注意的一点是,priority_queue的基本函数和queue基本一致,唯一的区别是queue有front()和back() 函数 ,但是priority_queue只有top(),也只能pop()出队列顶端元素。

2.关联式容器

  标准的关联式容器分为set(集合)和map(映射表),以及这两大类的衍生体multiset(多键集合)和multimap(多键映射表),这些容器的底层机制均以 RB-TREE (红黑树)完成。

2.1 set

   set和map容器不同,使用 set 容器存储的各个键值对,要求键 key 和值 value 必须相等。当使用 set 容器存储键值对时,只需要为其提供各键值对中的 value 值(也就是 key 的值)即可。
使用 set 容器存储的各个元素的值必须各不相同。
STL中的set底层也是RB-TREE(红黑树),集合中的每一个元素只出现一次,并且是排好顺序的(默认按照键值升序排列),访问元素的时间复杂度是O(log2 n)

在c++中,set的头文件是 #include<set>

set具有迭代器 set<int>::iterator i 定义一个迭代器,名为i 可以把迭代器理解为C语言的指针
set常用操作

set<int> q;     //以int型为例 默认按键值升序
set<int,greater<int>> p;  //降序排列 ,默认是升序排列
int x;
q.insert(x);	//将x插入q中
q.erase(x);		//删除q中的x元素,返回0或1,0表示set中不存在x
q.clear();		//清空q
q.empty();		//判断q是否为空,若是返回1,否则返回0
q.size();		//返回q中元素的个数
q.find(x);		//在q中查找x,返回x的迭代器,若x不存在,则返回指向q尾部的迭代器即 q.end()
q.lower_bound(x); //返回一个迭代器,指向第一个键值不小于x的元素
q.upper_bound(x); //返回一个迭代器,指向第一个键值大于x的元素

q.rend();		  //返回第一个元素的的前一个元素迭代器
q.begin();		  //返回指向q中第一个元素的迭代器

q.end();		 //返回指向q最后一个元素下一个位置的迭代器
q.rbegin();		 //返回最后一个元素

set单元素应用

#include<iostream>
#include<set>
using namespace std;
int main()
{
	set<int> q;   //默认按升序排列 
	q.insert(5);
	q.insert(5);
	q.insert(5);
	cout<<"q.size "<<q.size()<<endl;   //输出 1 ,在set插入中相同元素只会存在一个
	
	q.clear(); //清空set
	cout<<"q.size "<<q.size()<<"\n\n";
	
	q.insert(4);
	q.insert(4);
	q.insert(3);
	q.insert(3); 
	q.insert(2);
	q.insert(1);
	
	cout<<"lower_bound "<<*q.lower_bound(3)<<endl;  //返回3 
	cout<<"upper_bound "<<*q.upper_bound(3)<<"\n\n";  //返回4 
	
	set<int>::iterator i;
	for( i=q.begin();i!=q.end();i++)   //set的遍历 
		cout<<*i<<" ";				   //输出1 2 3 4,可见自动按键值排序 
	cout<<endl;
	
	q.erase(4);  //删除q中的 4 
	
	for(i=q.begin();i!=q.end();i++)  //再次遍历set 只输出 1 2 3 
		cout<<*i<<" ";
	cout<<"\n\n"; 
	
	
	set<int,greater<int>> p;  //降序排列 
	p.insert(1);
	p.insert(2);
	p.insert(3);
	p.insert(4);
	p.insert(5);
	for(i=p.begin();i!=p.end();i++)
		cout<<*i<<" ";
	cout<<endl;
	
	return 0;
}

set多元素应用(结构体)

#include<iostream>
#include<set>
using namespace std;
struct node{
	int a,b;
	bool operator< (const node W)const
	{
		return a>W.a;  //按a的值升序 
	}
}t;
int main()
{
	set<node> q;
	t.a=1;
	t.b=2;
	q.insert(t);
	
	t.a=4;
	t.b=2;
	q.insert(t);
	
	t.a=3;
	t.b=5;
	q.insert(t);	
	
	set<node>::iterator i;
	for(i=q.begin();i!=q.end();i++)
	{
		t=*i;
		cout<<t.a<<" "<<t.b<<endl;
	}
	return 0; 
}

 emsp;此外 STL还提供了unordered_set , unordered_set基于哈希表,数据插入和查找的时间复杂度很低,几乎是常数时间,而代价是消耗比较多的内存,无自动排序功能。底层实现上,使用一个下标范围比较大的数组来存储元素,形成很多的桶,利用hash函数对key进行映射到不同区域进行保存。
set与unordered相比:

1、set比unordered_set使用更少的内存来存储相同数量的元素。

2、对于少量的元素,在set中查找可能比在unordered_set中查找更快。

3、尽管许多操作在unordered_set的平均情况下更快,但通常需要保证set在最坏情况下有更好的复杂度(例如insert)。

4、如果您想按顺序访问元素,那么set对元素进行排序的功能是很有用的。

5、您可以用<、<=、>和>=从字典顺序上比较不同的set集。unordered_set集则不支持这些操作。

一般来说,在如下情况,适合使用set:

1、我们需要有序的数据(不同元素)。

2、我们必须打印/访问数据(按排序顺序)。

3、我们需要知道元素的前任/继承者。

一般来说,在如下情况,适合使用unordered_set:

1、我们需要保留一组元素,不需要排序。

2、我们需要单元素访问,即不需要遍历。

3、仅仅只是插入、删除、查找的话。

2.2 map

  现在有两类容器:map和unordered_map,对于多数应用到哈希表查找问题,采用unordered_map效率会高一些。下面对这二者的区别和联系做一个介绍。map的底层用的是红黑树,其是有序的,unordered_map的底层是哈希表,是无序的,整体而言map占用的内存更多但是查找的效率较低,而unordered_map占用的内存更高,但是由于底层是哈希表其查找的效率会高不少。

二、算法

sort(arr.begin(),arr.end(),greater()) // 降序排列
sort(arr.begin(),arr.end(),less()) // 升序排列
其他的百度即可,感觉用的不多,堆以及堆排的相关函数前面介绍了。

三、适配器

待更新!!!

参考文献

[1]. 侯捷,STL源码解析
[2] https://blog.csdn.net/u013317445/article/details/89680330
[3] https://blog.csdn.net/liitdar/article/details/80498634

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值