其他分享
首页 > 其他分享> > STL の 概念及其应用

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++++itit----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

LINK

  std::bitset 是标准库中的一个存储 0/1 的大小不可变容器。严格来讲,它并不属于 STL。

  由于内存地址是按字节即 byte 寻址,而非比特 bit,一个 bool 类型的变量,虽然只能表示 0/1, 但是也占了 1 byte 的内存。

  bitset 就是通过固定的优化,使得一个字节的八个比特能分别储存 8 位的 0/1

  对于一个 4 字节的 int 变量,在只存 0/1 的意义下,bitset 占用空间只是其 ,计算一些信息时,所需时间也是其 。

在某些情况下通过 bitset 可以优化程序的运行效率。至于其优化的是复杂度还是常数,要看计算复杂度的角度。一般 bitset 的复杂度有以下几种记法:(设原复杂度为 )

  1. ,这种记法认为 bitset 完全没有优化复杂度。
  2. ,这种记法不太严谨(复杂度中不应出现常数),但体现了 bitset 能将所需时间优化至 。
  3. ,其中 (计算机的位数),这种记法较为普遍接受。
  4. ,其中  为计算机一个整型变量的大小。

当然,vector 的一个特化 vector<bool> 的储存方式同 bitset 一样,区别在于其支持动态开空间,bitset 则和我们一般的静态数组一样,是在编译时就开好了的。

然而,bitset 有一些好用的库函数,不仅方便,而且有时可以避免使用 for 循环而没有实质的速度优化。因此,一般不使用 vector<bool>

 

使用

头文件

1
#include <bitset>

指定大小

1
bitset<1000> bs;  // a bitset with 1000 bits

构造函数

运算符

成员函数

一些文档中没有的成员函数:

标签:map,set,STL,复杂度,元素,概念,vector,bitset,应用
来源: https://www.cnblogs.com/pangtuan666/p/16527500.html