ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

STL の 概念及其应用

2022-07-28 10:02:07  阅读:132  来源: 互联网

标签:map set STL 复杂度 元素 概念 vector bitset 应用


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

构造函数

  • 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
    1. set(): 将整个 bitset 设置成 true
    2. set(pos, val = true): 将某一位设置成 true/false
    1. reset(): 将整个 bitset 设置成 false
    2. reset(pos): 将某一位设置成 false。相当于 set(pos, false)
    1. flip(): 翻转每一位。(,相当于异或一个全是  的 bitset
    2. 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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有