【第十七课】c++常用的STL容器

目录

pair

string

queue

priority_queue:优先队列

stack 

deque--双端队列

set -- multiset

map -- multimap  

无序关联容器

bitset:压位


上篇vector指路

stl : vector

pair

我们之前用到过一次,当时对他有了基本的了解,这里再回顾一下就好。内容不是很多。

pair用来存储两个相关联的数据,且这两个数据的数据类型可以不同。常说pair用来存储键值对。其使用时需要引头文件  #include  

pair的实现是一个结构体,第一个元素由 .first 进行索引,第二个元素使用  .second 索引。(注意这里使用时后面不用加括号()哦 )

pair的创建

    pair p;
    p={2,"ax"};

    pairq={1,2};
    pairr(1,1);
    auto s=make_pair('c',"sdv");
    //make_pair函数的主要优点是它可以自动推断出pair的类型,不需要显式地指定pair的类型

    pair> t;
    //嵌套的 pair 可以用来组织和表示具有层次结构的数据,其中不同层次的信息被封装在不同的元素中

注意写的格式,哪里是() 哪里是{ } 区分清楚 

p.first;//获取第一个元素
p.second;//获取第二个元素

当两个pair要进行比较的时候,一般是按照字典序,以第一个元素优先比较,当两个pair的第一个元素相同时,才会比较第二个元素

string

string也算比较常用了。其头文件是 #include  

    string c;
    
    c.size();
    c.empty();
    c.length();//和size一样

    c+='c';
    c+="vf";
    //如果我们是以string创建字符串(也就相当于一个字符数组),用+=运算符来读入下一个字符,实际上是字符/字符串的连接
    //这可以类比为逐个字符读取并将其连接到字符串的过程,因为每次读取一个字符,都将其追加到字符串的末尾

    //c++中的substr()函数,第一个参数是起始位置,第二个参数是子串长度。 但大部分其它语言中第二个参数表示截至位置
    c.substr(1,2);//返回第1-2个字符
    c.substr(1);//直接返回从第一个字符开始的整个子串
    c.substr(1,5);
    //如果我们第二个参数的位置写出的数字要大于整个字符串的长度,那么会输出从第一个参数所对数字的位置开始,到字符串的末尾
    
    cout<

常用的就都写在代码里了。

当然它也包含 size()计算字符串大小(不包含末尾结束符 '\0' )   /  clear()清空字符串  / empty() 判断字符串是否为空

但是c语言中的sizeof会包含   '\0'  ,因为C风格的字符串是一个字符数组,数组的最后一个元素是结束标志\0。sizeof运算符返回的是整个数组(包括\0)所占用的字节数

注意区分:strcmp 也是我们比较字符串常用的函数。这里要分清楚,在c++中使用该函数,要引头文件  #include

queue

队列遵循先进先出

    queue q;//创建了一个元素都为int类型的队列

    q.size();
    q.empty();
    q.back();//返回队列末尾元素
    q.pop();//弹出队头元素
    q.push(1);//向队尾插入元素    
    q.front();//返回队头元素

    //queue没有自带的clear() 清空队列元素的函数
    //如果想要清空
    q=queue();

注意它没有自带的clear()函数 

其头文件是#include 

priority_queue:优先队列

其是靠堆来实现的。需要回顾的可以看一下

数据结构:堆

要注意的是,优先队列的堆:默认是大根堆

没有自带的clear()函数 

优先队列的创建 

    priority_queue q;//创建了一个元素是int类型的优先队列,即大根堆

    //如果想要创建小根堆,可以在插入元素的时候,插入原数的负数形式
    q.push(-x);
    //也可以
    priority_queue,greater> q;//注意引vector的头文件
    //这样所创建的就是一个小根堆

注意其头文件也是 #include 

常用函数

    q.empty();
    q.size();
    q.pop();//弹出堆顶
    q.push(1);//插入一个元素,会自动插入到符合堆的性质的位置
    q.top();//返回堆顶元素

stack 

栈遵循先进后出

    stack s;
    s.pop();//弹出栈顶元素
    s.push(1);//向栈顶插入一个元素
    s.top();//返回栈顶元素
    s.size();
    s.empty();

头文件是  #include

没有内置clear() 函数 

deque--双端队列

其实是一个加强版的vector。很多函数都包含,但是由于速度实在太慢,不太常用。

    deque d;
   
    d.size();
    d.empty();
    d.clear();//清空队列

    d.back();//返回最后一个元素
    d.front();//返回队首元素
    d.pop_back();//弹出最后一个元素
    d.push_back(1);//在队尾插入一个元素
    d.pop_front();//弹出队首元素
    d.push_front(2);//在队头插入元素

    d[1];//支持数组形式的随机寻址

    //支持迭代器
    d.begin();
    d.end();

头文件 #include 

这里强调一下随即寻址d[1]   ,vector也是支持随机寻址的。

set -- multiset

使用时头文件 #include 

    set s;//如果我们向set中插入一个重复的元素,那程序会忽略掉这个操作
    multiset q;//multiset中可以有重复元素

    s.size();
    s.empty();
    s.clear();

    s.insert(1);//插入元素
    s.insert(2);

    s.erase(1);
    //这里我们写的是删除值为1的元素,那么会删除所有值为1的元素
    //如果我们传入的参数写的是该元素的迭代器,那么会删除之后并回下一个元素的迭代器

    //注意如果要删除一个范围内的元素的erase函数,那么应该使用参数是两个迭代器,而不是数字
    s.erase(s.begin(),s.begin()++);//删除该区间内的元素,并返回下一个元素的迭代器

    s.upper_bound(1);//返回第一个>1的元素的迭代器
    s.lower_bound(1);//返回第一个>=1的元素的迭代器
    s.count(1);//返回某个元素的个数
    s.find(1);//查找一个数,如果这个数存在,就返回其迭代器,若不存在返回set.end()
    s.begin();
    s.end();

关于迭代器:我们上篇里说过:

这里补充迭代器可以进行的操作,这里 set 和 multiset 以及下面要说的 map 和 multimap 的迭代器都是可以进行 ++ -- 操作的

【第十七课】c++常用的STL容器_第1张图片

map -- multimap  

这和上面的set组合基本函数都差不多。这里不在重复写了。

头文件是 #include

map和multimap是两种常用的关联式容器,它们都是基于键值对的数据结构,这两种容器的主要区别在于,map不允许两个元素有相同的键值,而multimap允许键值重复  

 set组合和map组合的区别

【第十七课】c++常用的STL容器_第2张图片

也就是他们的区别是一个是存储两个值(要使用pair),一个只存储一个值

map的创建以及键值的映射关系

    //类似于数组,但是map这样的寻址时间复杂度是O(logn) 而数组是O(1)
    //map的第一个参数是“键” 第二个参数是“值”
    map a;

    a[1]=2;

    map b;
    b["cd"]=1;

    map c;
    c[2]="fe";

函数

    a.size();
    a.empty();
    a.clear();

    a.find(10);//查找以该元素为“键”的键值对的迭代器
    a.insert(pair(10,10));//函数参数是pair类型的键值对
    a.count(10);//参数是以该值为“键”的元素个数
    a.erase(a.begin());//参数是一个迭代器
    //同样也有两个迭代器参数删除一整个区间元素的写法,返回的是下一个元素的迭代器
    a.upper_bound(10);
    a.lower_bound(10);//对于这两个函数参数是“键”,返回迭代器

无序关联容器

unordered_set

unordered_map

unordered_multiset

unordered_multimap 

这四个名字很直接,就是表示是无序的。

无序容器的底层实现是哈希表,因此它们的插入、删除和查找操作的平均时间复杂度都是O(1)。然而,由于它们是无序的,所以不支持lower_bound()、upper_bound()函数,也不支持迭代器的++和--操作

bitset:压位

bitset 是一个位集合的模板类,用于表示固定大小的位序列。bitset 以非常高效的方式存储位信息,每个位都只占用一个比特(0或1),并且支持各种位运算操作。“压位”通常指的是使用 bitset 进行位操作。

我们可以把它看作是一个数组,只不过这个数组的每个元素只能是0或1(即二进制位)。 

这是洛谷上一篇关于bitset的文章,感觉写的很详细,可以看一下

扶苏的bitset浅谈 

常用函数 

    bitset<1000> b;
    b.any();//判断是否至少有一个1
    b.none();//判断是否全为0
    b.count();//返回1的个数
    b.set();//把所有位置置1
    b.set(1);//将第一个位置置1
    b.set(k,v);//将第k位置为v
    b.reset();//把所有位置置0
    b.reset(1);//将第一个位置置0
    b.flip();//将所有位取反~
    b.flip(k);//把第k位取反

我们上面所提到的容器,<>尖括号内部写的都是元素类型,但是bitset<>尖括号里写的是元素个数。 

bitset有一些好处:

1. 空间上的优化:bitset中的每个元素只占1 bit,相当于一个char元素所占空间的八分之一。这使得bitset在处理大量二进制数据时,比使用bool数组或其他数据结构更加节省空间。

2.位运算上的便利:bitset重载了许多二进制运算符,如&、|、^、~ 、>>、<< 等使其支持类似于整数类型的位运算操作。而且可以处理任意长度的二进制数据,而整数类型的长度是固定的。这里主要是指编程的便利性和代码的可读性,而不是运行时的性能优化

3含有很多内置函数:方便各种操作。 

例如,假设要实现一个功能,需要跟踪1000个不同的选项,每个选项都可以打开或关闭。可以使用一个bitset来表示这些选项的状态,其中每一位代表一个选项,1表示选项打开,0表示选项关闭。这样,就可以使用一个bitset对象来代替1000个单独的bool变量

这里给出bitset快速进行二进制与十进制的转换的代码

#include 
#include 
using namespace std;

int main() {
    bitset<8> bs1(42); // 将整数42转换为二进制
    cout << bs1 << endl; // 输出 "00101010"

    bitset<8> bs2("11010101"); // 将二进制字符串转换为bitset
    cout << bs2.to_ulong() << endl; // 输出 "213"  
    //to_ulong()成员函数可以将bitset对象转换为一个无符号长整型数
    return 0;
}

好了,第二部分数据结构结束了。

有问题欢迎指出!一起加油!!!

你可能感兴趣的:(算法--学习笔记,c++)