STL の 概念及其应用
作者:互联网
1.队列queue
queue是STL中实现“先进先出”的一个容器。 使用queue。必须加#include<queue>
及using namespace std
; queue<typename> name;
常用函数:
(1) push() :将x入队,时间复杂度为O(1)。
(2) front()和back() :它们分别用来获得队首元素和队尾元素,时间复杂度为O(1),
queue<int> q;
for(int i = 1; i <= 5; i ++)
q.push(i);
printf(“%d %d\n”, q.front(), q.back());
(3) pop() :用来让队首元素出队,时间复杂度为O(1)。
(4) empty() :用来检测queue是否为空,返回true或者false,时间复杂度为O(1)。需要注意,在使用front()和pop()前,必须用empty()来判断队列是否为空。
(5) size() :返回queue内元素的个数,时间复杂度为O(1)。
2、栈stack
stack是STL中实现“后进先出”的一个容器。 使用stack,必须加#include<stack>
及using namespace std;
stack<typename> name;
常用函数:
(1) push() :push(x)将x压栈,时间复杂度为O(1)。
(2) top() :用来获得栈顶元素,时间复杂度为O(1),例如以下代码输出5:
stack<int> st;
for(int i = 1; i <= 5; i ++)
st.push(i);
printf(“%d\n”, st.top());
(3) pop() :用来弹出栈顶元素,时间复杂度为O(1),注意pop()是删不是取。
(4) empty() :用来检测stack是否为空,空返回true,非空返回false,时间复杂度 为O(1)。
(5) size() :size()返回stack内元素的个数,时间复杂度为O(1)。
3.变长数组vector
vector直译为“向量”,一般说成“变长数组”,也就是长度根据需要而自动改变的数组,有些题目需要开很多数组,往往造成内存超限,使用vector简单方便,还可节省空间,使用vector,必须加#include<vector>
及using namespace std;
。
vector<typename> name;
以上定义相当于定义了一个一维数组name[size],只是size不确定,其长度可以根据需要而变化。其中,typename可以是任何基本类型,如int、double、char、结构体等,也可以是容器。
vector<int> a; //定义了一个整型不定长数组a
vector<double> score; //定义了一个双精度浮点型不定长数组score
vector<node> stu; //定义了一个结构体类型的不定长数组stu
注意:如果typename也是一个STL容器,那么定义时需要在两个“>”符号之间加一个空格,不然编译器会误认为是位运算的右移符号“>>”,例如:
vector<vector<int> > a; //定义了一个两个维度都可变的二维整型数组a
vector<int> a[100]; //定义了一个第一维长度为100,第二位不限长度的二维数组a
vector的访问:
访问vector中的元素一般有两种方式:下标访问 和 迭代器(iterator)访问。
第一种是通过“下标”访问的。例如,对于容器vector<int> v,可以使用v[index]来访问它的第index个元素。其中,0≤index≤v.size() – 1
。
第二种是通过“迭代器”访问的。可以将迭代器理解为一种类似指针的变量,使用前需要提前定义,其定义为:vector<typename>::iterator it
,这个it就是一个迭代器,可以通过“*it”来访问该容器里的元素值,下面举个例子:
vector<int>::iterator it = v.begin(); //定义一个迭代器it,初始化为容器v的首元素地址,这是*it相当于v[0],*(it + i)相当于v[i]。
迭代器还可以进行自加自减操作,如it++
,++it
,it--
,--it,
注意:迭代器不支持“it<v.end()”的写法,只能是“it != v.end()”, v.end()并不是取v容器尾元素地址,而是尾元素下一个地址。 例:
for(vector<int>::iterator it = v.begin(); it != v.end(); it ++)
printf(“%d”,*it);
常用函数:
(1) push_back() :push_back(x)将x添加到容器最后,时间复杂度为O(1)。
(2) size() :如果是一维数组,size()用来获得vector中元素个数;如果是二维数组,size()用来获得vector中第二维的元素个数,时间复杂度为O(1),同时,还可以使用resize(n)重设数组大小。例如以下代码输出12300:
vector<int> v;
for(int i = 1; i <= 3; i ++) v.push_back(i);
v.resize(5);
for(int i = 0; i < v.size(); i ++) printf(“%d”,v[i]);
(3) pop_back() :用来删除vector中的尾元素。时间复杂度为O(1),例如以下代码输出12:
(4) clear() :用来清空vector中的所有元素。时间复杂度为O(n),例如以下代码输出0:
(5) insert() :insert(it, x)用来向vector任意迭代器it前插入元素x。时间复杂度为O(n),例如以下代码输出1 2 -1 3 4 5:
vector<int> v;
for(int i=1;i<=5;i++) v.push_back(i);
vector<int>::iterator it=v.begin();
v.insert(it+2,-1);
for(;it!=v.end();it++) printf("%d ",*it);
(6) erase() :erase()用来删除vector中的元素,有两种用法,一是erase(it),删除迭代器it处的单个元素;二是erase(first, last),删除左闭右开区间[first, last)内的所有元素。例如:
4、优先队列priority_queue
priority_queue翻译为优先队列,一般用来解决一些贪心问题,其底层是用堆来实现的。在优先队列中,任何时刻,队首元素一定是当前队列中优先级最高的那一个。使用优先队列,也必须加#include<queue>
及using namespace std;
。
priority_queue<typename> name;
注意:和queue不一样的是,priority_queue没有front()和back(),而只能通过top()或pop()访问队首元素(也成为堆顶元素),也就是优先级最高的元素。
常用函数:
(1)push():push(x)是将x加入优先队列,时间复杂度为O(log2n),n为当前优先队列中的元素个数。加入后会自动调整priority_queue的内部结构,以保证队首元素(堆顶元素)的优先级最高
(2)top() :top()是获取队首元素(堆顶元素),时间复杂度为O(1)。
(3)pop() :pop()是让队首元素(堆顶元素)出队,由于出队后要调整堆内部结构,所以时间复杂度是O(log2n)
优先队列优先级如何设置:
//大根堆优先队列的定义:
priorty_queue<int> q; //默认为大顶堆优先队列
priorty_queue<int,vector<int>,less<int> > q;
//小根堆优先队列的定义:
priorty_queue<int,vector<int>,greater<int> > q;
5、映射map
map翻译为映射,其实数组就是一种映射。比如int a[100];
,就是定义了一个int到int的映射,而a[5]=25;
是把下标5映射到值25,他们是一一对应的,数组总是把int类型映射到其它基本类型,因为数组下标只能是int。但有时希望把string映射成一个int,数组就不方便了这时就可以使用map,它可以将任何基本类型(包括容器)映射到任何基本类型。 使用map,也必须加#include<map>
及using namespace std;
。
map常用的三种情形:
1.需要建立字符(串)与整数之间的映射,使用map可以减少代码量;
2.判断大整数(比如几千位)或者其它类型数据是否存在,可以把map当bool类型数组使用(哈希表);
3. 字符串与字符串之间的映射。
定义:
map<typename1, typename2> name;
其中,typename1是映射前的类型(键key),typename2是映射后的类型(值value),name为映射的名字,例:
普通int数组就是:map<int, int> mp;
字符串到整型的映射:map<string, int> mp;
键和值也可以是容器:map<set<int>, string> mp;
当然,map的键对值必须唯一(也就是键key必须唯一,值value不一定)
map的访问:
map的访问依然是下标访问和迭代器访问两种。
下标访问(例): map<char, int> mp;
用mp[‘c’]
来访问它对应的元素,如mp[‘c’] = 124
。
迭代器访问(例): map<typename1, typename2>::iterator it
; 因为map的每一对映射都有两个typename,所以使用“it -> first”来访问键,而使用“it -> second”来访问值。例如:
map<char, int> mp;
mp[‘m’] = 20; mp[‘r’] = 30; mp[‘a’] = 40;
for(map<char, int>::iterator it = mp.begin(); it != mp.end(); it ++)
printf(“%c %d\n”,it -> first, it -> second);
map在建立映射的同时,会自动实现按照键从小到大排序。因为map内部使用“红黑树”实现,后面set也是。
map的常用函数:
(1)find() 和 size() :find(key)是返回键为key的映射的迭代器,时间复杂度为O(log2n),n为map中映射的对数。size()用来获得map中映射的对数,时间复杂度为O(1)。
(2)erase() :erase()可以删除单个元素,也可以删除一个区间内的所有元素。删除单个元素可以用erase(it),其中it为要删除元素的迭代器,时间复杂度为O(1)。也可以用erase(key),key为要删除元素的键,时间复杂度为O(log2n)。删除一个区间内所有元素用erase(first, last)。其中,first为区间的起始迭代器;last为区间的末尾迭代器的下一个地址,也就是左闭右开区间[first, last) 。时间复杂度为O(first - last)。
(3)clear() :用来清空map。时间复杂度为O(n)。
6.二元结构体pair
pair是”二元结构体”的替代品,将两个元素捆绑在一起,节省编码时间。相当于一下定义:
struct pair {
typename1 first;
typename2 second;
};
要使用pair,必须先添加头文件,即#include<utility>
,同时需要using namespace std;
。因为map的内部实现涉及pair,因此添加map头文件时会自动添加utility头文件,此时可以省去utility头文件。
pair<typename1, typename2> name;
初始化:例如:定义一个参数为string和int类型的pair,并同时初始化:
写法一:make_pair(“haha”, 5);
写法二:pair<string, int> p(“haha”, 5);
写法三
pair<string, int> p;
p.first = “haha”;
p.second = 5;
pair可以直接做比较运算,比较的规则是先以first的大小作为标准,只有当first相等时才去判断second的大小。
由于map可以根据键值自动排序,而pair又可以比较大小,所以pair可插入到同类型的map中并根据it->first排序,(注意,如果it->first相同则根据map键值唯一的特性,只保留先输入的二元组)
7.集合set
set翻译为集合,是一个内部自动有序且不含重复元素的容器。set最主要的作用就是自动去重并按升序排序,因此遇到需要去重但是又不方便直接开数组的情况,比如元素比较多或者类型不是int,可以尝试用set解决。set中的元素是唯一的,其内部采用“红黑树”实现。 使用set,也必须加#include<set>
及using namespace std;
。
set<typename> name;
其中,typename可以是任何基本类型或者容器,name是集合的名字,例: set<int> st;
也可以定义set数组,例:set<int> st[100];
这样st[0] ~ st[99]中的每一个元素都是一个set容器。
set的访问:
set只能通过迭代器访问,即先定义一个迭代器: set<typename>::iterator it;
然后使用“*it”来访问set中的元素。Set也不支持“*(it+i)”和“it<st.end()”的访问方式,实际上除了vector和string之外的STL容器都不支持。
set的常用函数:
(1)insert() 和 size() :insert(x)用来将x插入到set中,并自动递增排序和去重,时间复杂度为O(log2n),n为set中元素的个数。size()用来获得set中的元素个数,时间复杂度为O(1)。
(2)find() :find(value)是返回set中对应值value的迭代器(可以把it看成地址,*it看成地址对应的值),时间复杂度为O(log2n)。例如以下一段代码输出“3 2”。
set<int> st;
for(int i = 1; i <= 3; i ++) st.insert(i);
printf(“%d”, st.size());
printf(“%d”, *(st.find(2)));
(3)clear():clear()用来清空set中的所有元素,时间复杂度为O(n)。
(4)erase() :erase()可以删除单个元素,也可以删除一个区间内的所有元素。删除单个元素可以用erase(it),其中it为要删除元素的迭代器,时间复杂度为O(1)。也可以用erase(value),value为要删除元素的值,时间复杂度为O(log2n)。删除一个区间内所有元素用erase(first, last)。其中,first为区间的起始迭代器;last为区间的末尾迭代器的下一个地址,也就是左闭右开区间[first, last) 。时间复杂度为O(first - last)。
8.bitset
std::bitset
是标准库中的一个存储 0/1
的大小不可变容器。严格来讲,它并不属于 STL。
由于内存地址是按字节即 byte
寻址,而非比特 bit
,一个 bool
类型的变量,虽然只能表示 0/1
, 但是也占了 1 byte 的内存。
bitset
就是通过固定的优化,使得一个字节的八个比特能分别储存 8 位的 0/1
。
对于一个 4 字节的 int
变量,在只存 0/1
的意义下,bitset
占用空间只是其 ,计算一些信息时,所需时间也是其 。
在某些情况下通过 bitset
可以优化程序的运行效率。至于其优化的是复杂度还是常数,要看计算复杂度的角度。一般 bitset
的复杂度有以下几种记法:(设原复杂度为 )
- ,这种记法认为
bitset
完全没有优化复杂度。 - ,这种记法不太严谨(复杂度中不应出现常数),但体现了
bitset
能将所需时间优化至 。 - ,其中 (计算机的位数),这种记法较为普遍接受。
- ,其中 为计算机一个整型变量的大小。
当然,vector
的一个特化 vector<bool>
的储存方式同 bitset
一样,区别在于其支持动态开空间,bitset
则和我们一般的静态数组一样,是在编译时就开好了的。
然而,bitset
有一些好用的库函数,不仅方便,而且有时可以避免使用 for 循环而没有实质的速度优化。因此,一般不使用 vector<bool>
。
使用
头文件
|
|
指定大小
|
|
构造函数
bitset()
: 每一位都是false
。bitset(unsigned long val)
: 设为val
的二进制形式。bitset(const string& str)
: 设为 串str
。
运算符
operator []
: 访问其特定的一位。operator ==/!=
: 比较两个bitset
内容是否完全一样。operator &/&=/|/| =/^/^=/~
: 进行按位与/或/异或/取反操作。bitset
只能与bitset
进行位运算,若要和整型进行位运算,要先将整型转换为bitset
。operator <>/<<=/>>=
: 进行二进制左移/右移。operator <>
: 流运算符,这意味着你可以通过cin/cout
进行输入输出。
成员函数
count()
: 返回true
的数量。size()
: 返回bitset
的大小。test(pos)
: 它和vector
中的at()
的作用是一样的,和[]
运算符的区别就是越界检查。any()
: 若存在某一位是true
则返回true
,否则返回false
。none()
: 若所有位都是false
则返回true
,否则返回false
。all()
:C++11,若所有位都是true
则返回true
,否则返回false
。-
set()
: 将整个bitset
设置成true
。set(pos, val = true)
: 将某一位设置成true
/false
。
-
reset()
: 将整个bitset
设置成false
。reset(pos)
: 将某一位设置成false
。相当于set(pos, false)
。
-
flip()
: 翻转每一位。(,相当于异或一个全是 的bitset
)flip(pos)
: 翻转某一位。
to_string()
: 返回转换成的字符串表达。to_ulong()
: 返回转换成的unsigned long
表达 (long
在 NT 及 32 位 POSIX 系统下与int
一样,在 64 位 POSIX 下与long long
一样)。to_ullong()
:C++11,返回转换成的unsigned long long
表达。
一些文档中没有的成员函数:
_Find_first()
: 返回bitset
第一个true
的下标,若没有true
则返回bitset
的大小。_Find_next(pos)
: 返回pos
后面(下标严格大于pos
的位置)第一个true
的下标,若pos
后面没有true
则返回bitset
的大小。
标签:map,set,STL,复杂度,元素,概念,vector,bitset,应用 来源: https://www.cnblogs.com/pangtuan666/p/16527500.html