C++标准模板库STL(算法题使用)

由于自己之前并不常用STL库,而STL库在很多算法中能够节省很多自己手打数据结构的时间,故这里开一个笔记来重新学习一下,也方便自己之后能够复习。

Vector 的常见用法详解

【简介】vector翻译为向量,我觉得用‘变长数组’来解释他更为合适。利用vector可以避免超内存等情况,节省空间。也可以用邻接表的方式来存储图。 使用vector头文件是 vector 需要 include.
1,vector定义
单独定义一个vector:

vector<typename> name;

上面这个定义其实相当于定义了一个一维数组 name[SIZE],只不过其长度可以根据需要进行变化。 这里的typename 可以是任何数据类型。
如果typename 也是 vector

vector<vector<typename>> name; 

这里很容易联想到二维数组的定义,我们可以认为其是两个维度都可变长的二维数组。
然后是vector数组 的方法:

vector<typename> Arrayname[arraysize];

这样 Arrayname[0] ~ Arrayname[arraysize-1]都是一个vector容器。 这里是一个维度固定的二维数组。
2,vector容器内元素的访问

  • 通过下标访问。
    和访问普通数组一样,对于 vector<typename> vi; 直接通过 vi[index 访问即可。这里的下标是从 0 到 vi.size()-1 访问这个范围外的元素可能会出错。

  • 通过迭代器访问。
    迭代器(iterator)可以理解是一种类似指针的东西,其定义是:

    vector<typename>::iterator it;
    

    这样得到了迭代器it,并且可以通过*it 来访问vector的元素。
    例如,这里有一个vector容器:

    vector<int> v1;
    for(int i = 1;i <= 5; i++){
        vi.push_back(i);
    }
    

    可以通过下面的方式进行访问容器内的元素

    vector<int>::iterator it = vi.begin();
    for(int i=0;i < 5; i++){
    	printf("%d ",*(it + i)); //输出 vi[i]
    } 
    

    从这里可以看出 vi[i]和*(vi.begin()+ i ) 是等价的。
    这里begin()是取vector头元素的地址,这里引出 end() 这里需要注意 end() 是取vector末尾元素地址的下一个地址,不存储任何元素。故这里有了另一种遍历vector 的方法。

    for(vector<int>::iterator it = vi.begin(); it != vi.end() ; it++){
    	printf("%d ", *it);
    }
    

    最后需要指出,在常用的STL容器中,只有vector 和 string 中,才允许使用vi.begin()+3这种迭代器加上整数的写法。
    3,vector常用函数实例解析
    (1)push_back
    顾名思义,push_back(x)就是在vector尾元素添加一个元素x,时间复杂度 O(1)。
    (2)pop_back
    即删除vector的尾元素。
    (3)size()
    用来获取vector中元素的个数。返回unsigned类型。
    (4)clear()
    用来清空vector中的所有元素。
    (5)insert()
    insert(it,x)用来向vector的任意迭代器it处插入一个元素x。
    (6)erase()
    两种用法:删除单个元素,删除一个区间的所有元素。
    ①删除单个元素。 erase(it)即删除迭代器为it处的元素。
    ②删除一个区间所有的元素,erase(first,end),删除[first,last)内的所有元素。
    4,vector的常见用途
    (1)存储数据
    (2)用邻接表存储图

set 的常见用法详解

【简介】set翻译为集合,是指一个内部自动有序且不含重复元素的容器。考试中,有可能出现需要去掉重复元素的情况,这时候就可以用set来保留元素本身不考虑其个数。使用set需要添加 <set>。
1,set的定义
单独定义一个set

set<typename> name;

这里的写法和vector基本一样,或者说大部分的STL都是这样定义的,typename可以是任何基本类型。 这里不再介绍各个数组之类的定义方式,和vector基本一样。
2,set容器内元素的访问
set只能通过迭代器(iterator)访问。定义方式和vector的迭代器定义方式一样。由于除了 vector和stirng 之外的迭代器都不只除 *(it + i) 的访问方式,因此只能按照下面方式枚举。

\#include<stdio.h>
\#include<set>
using namespace std;
int main(){
	set<int> st;
	st.insert(3);
	st.insert(5);
	st.insert(2);
	st.insert(3);
	for(set<int>::iterator it = st.begin();it != st.end(); it++){
		printf("%d ", *it );
	}
	return 0;
}

这里的输出结果为 2 3 5。
3,set常用函数实例解析
(1) insert()
insert(x)可将x插入set容器中,并自动递增排序和去重。
(2)find()
find(value)返回set中对应值为value的迭代器。
(3)erase()
erase也有两种用法:删除单个元素,删除区间内元素
①删除单个, st.erase(it),it为所要删除元素的迭代器。可以结合find()函数来表示
st.erase(value),value为所要删除的元素的值。
②删除一个区间的所有元素。 st.erase(first,last)可以删除一个区间所有的元素,first和last为迭代器形式,注意删除为[first,last) 左闭右开。
(4)size()
用来获得set内元素的个数。
(5)clear()
clear() 用来清空set中所有的元素。
3,set的常见用途
主要作用是自动去重并按照升序进行排序。

string的常见用法详解

【简介】在C语言中,一般用字符串数组 char str[] 来存放字符串。使用string会更加的方便。如果要使用string,需要包含 string头文件,注意 string.h和string是不一样的头文件。
1,string的定义
定义 string 的方式和基本数据类型相同,只需要在string 上跟上变量名(可进行初始化)即可:

string str;
string str = "abcd";

2,string中内容的访问
(1)通过下标访问
一般来说,可以直接像字符数组那样去访问string:

for(int i=0;i < str.length(); i++){
	printf("%c ",str[i]);
}

输出结果就是 abcd 。
如果要读入或者输出整个字符串,则只能用cin 和 cout:(如果想用printf输出string,需要利用c_str()函数将string类型转换为字符数组来进行输出)

string str;
cin>>str;
cout<<str;
printf("%s\n",str.c_str());

(2)通过迭代器访问
因为有些函数如insert()和erase()要求迭代器为参数,因此还是需要学习一个string迭代器的用法。
由于string不像其他STL容器需要参数,故可以这样定义迭代器。

string::iterator it;

这样就得到了迭代器it,并且可以通过*来访问string的每一位。

string str = "abcd";
for(string::iterator it = str.begin(); it != str.end(); it++){
	printf("%c ", *it);
}

3,string常用函数实例解析
string的函数有很多,这里只调出几个主要的。
(1)operator+=
这是string的加法,可以直接将两个string拼接起来。

string str1 = "abc", str2 = "xyz";
str1 += str2; //将str2直接拼接到str1上

(2)compare operator
两个string类型可以用 ==,!= , < , <= , > , >=进行比较大小,比较规则是字典序。
(3)length()/size()
length()返回stirng的长度,即存放的字符数。size()和length()基本相同。
(4) insert()
string的insert()函数有很多写法,这里给出几个常用的写法。
①insert(pos,string),在pos号位置中插入字符串string。
②insert(it,it2,it3),it为字符串的欲插入位置,it2和it3为待插入字符串的首尾迭代器,用来表示串[it2,it3)将被插入在it的位置上。
(5)erase()
erase()有两种用法:删除单个元素,删除一个区间的所有元素。
①删除单个元素:erase(it)用于删除单个元素,it为所需要删除的元素的迭代器。
②删除一个区间所有元素,erase(first,last),同理,删除[first,last),first和last为相应的迭代器。这里还有一种用法,str.erase(pos,length),pos为需要开始删除的起始位置,length为删除的字符个数。
(6)clear()
clear()用于清空string的数据。
(7)substr()
substr(pos,len)返回从pos号位开始,长度为len的字串
(8)string::npos
string::npos是一个常数,其本身的值为-1,但是由于是unsigned_int类型,因此实际上也可以认为其是unsigned_int类型最大值,string::npos用以作为find函数匹配失败的返回值。
(9)find()
str.find(str2),当str2是str的子串时,返回其在str中第一次出现的位置,如果str2不是str的子串,返回string::npos。
str.find(str2,pos),从str的pos号位开始匹配str2,返回值和上相同。
(10)replace()
str.replace(pos,len,str2)把str从pos号位开始,长度为len的子串替换为str2。
str.replace(it1,it2,str2)把str的迭代器[it1,it2)范围的子串替换为str2。

map的常用用法详解

【简介】 map翻译为映射。在定义数组时(int array[100]),其实是定义了一个从int型到int型的映射,比如array[0] = 25,array[4] =36就分别是将0映射到25,将4映射到36.一个double型数组则是将int映射到double型,这里不再介绍。这样,当我们需要其他类型作为关键字来作映射,会显得不太方便。这时可以用到map,因为map可以将任何基本类型(包括STL的容器)映射到任意基本类型。
1,map的定义
单独定义一个map

map<typename1,typename2> mp;
map<string,int> map;  //字符串映射int型 必须用string
map<set<int>,string> mp;  //可以让STL容器作为键

上述代码中,第一个是键的类型,第二个是值得类型。注意如果是字符串到整型得映射,必须用string而不能用char数组。
2,map容器内元素得访问
map有两种访问方式:下标和迭代器

  • 通过下标访问
    和普通数组一样,例如对于 map<char,int> mp 得map来说,可以使用 mp[‘c’] 来访问对应对应得整数。当建立映射时,可以用mp[‘c’] = 20这样和普通数组一样得方式。但是要注意的是,map中得键是唯一的
  • 通过迭代器访问
    map得迭代器定义和其他得STL容器迭代器定义得方式一样
    map<typename1,typename2>::iterator it;
    
    typename1 和 typename2 就是定义map时填写得类型,这样就得到了迭代器it。
    map迭代器得使用方式和其他STL容器得迭代器不同,因为map得每一对映射都有两个typename,这决定了必须能通过一个it来同时访问键和值。事实上,map可以使用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);
    }
    
    结果:
    a 40
    m 20
    r 30
    
    这里似乎有一个很神奇的现象:map会以键从小到大的顺序自动排序,这是由于map内部使用红黑树实现的(set也是),在建立映射会自动实现从小到大的排序功能。
    3,map常用函数实例解析
    (1)find()
    find(key)返回键为key的映射的迭代器。
    (2)erase()
    有两种用法: 删除单个元素,删除一个区间额你的所有元素。
    ①删除单个元素:map.erase(it),it为需要删除的元素的迭代器。
    示例如下:
map<char,int> mp;
mp['a'] = 1;
mp['b'] = 2;
mp['c'] = 3;  
map<char,int>::iterator it = mp.find('b');
mp.erase(it);  //这里删除了 b 2

第二种方式,mp.erase(key),key为欲删除的映射的键。
②删除一个区间的所有元素。mp.erase(first,last),其中first为需要删除的区间的起始迭代器,而last则为需要删除的区间的末尾迭代器的一个地址,也为左闭右开的区间[first,last)。
(3)size()
size()用来获取map中映射的对数。
(4)clear()
clear()用来清空map中的所有元素。
4,map的常见用途
感觉map能用到的地方应该算是比较多的。

  • 需要建立字符和整数之间映射的题目。
  • 判断大整数或其他数据是否存在的题目,吧map当bool数组使用。
  • 字符串和字符串的映射也可能会遇到。
    **扩展:map的键和值是唯一的,如果一个键需要对应多个值,只能用multimap。另外,C++11还加了unordered_map,以散列代替map内部的红黑树实现,使其可以用来处理只映射而不按key排序的需求,速度会很快。

queue的常见用法详解

【定义】queue翻译为队列,是一种很常见的数据结构。STL实现了一个先进先出的容器。使用时需要添加 queue的头文件。
1,queue的定义

queue<typename> name;

2,queue容器内元素的访问
由于队列本身是一种先进先出的限制性数据结构,因此再STL中只能用front()来访问队首元素,或者是back()来访问队尾元素。
3,queue常用函数实例解析
(1)push()
push(x)将x进行入队。
(2)front(),back()
front和back分别获取队首元素和队尾元素。
(3)pop()
pop()令队首元素出队。
(4)empty()
empty()检测queue是否为空。
(5)size()
size()返回queue内元素的个数。
4,queue的常见用途
当需要进行BFS时,可以直接用queue进行代替
有一点可能需要注意,再使用front()和back()之前,先用empty()判断队列是否为空,否则可能会出现错误。

dque双端队列

使用方法:

#include<deque>
//初始化定义
deque<int> dq;

插入元素:

  • push_back(value): 在deque的尾部插入一个元素。
  • push_front(value): 在deque的头部插入一个元素。
  • insert(const_iterator pos, const T& value)   主要用于插入元素到容器的指定位置
    删除元素:
    pop_back(): 删除deque的尾部元素。
    pop_front(): 删除deque的头部元素。

访问元素:
front(): 返回deque的头部元素的引用。
back(): 返回deque的尾部元素的引用。

判断容器是否为空:
empty(): 如果deque为空,则返回true;否则返回false。

获取容器的大小:
size(): 返回deque中元素的个数。

清空容器:
clear(): 删除deque中的所有元素,使其变为空。

priority_queue的常见用法详解

【简介】 priority_queue又称为优先队列,其底层是用堆来实现的。在优先队列中,队首元素一定是当前队列中优先级最高的哪一个。如队列有如下元素,且定义好了优先级:

桃子 (优先级3)
梨子 (优先级4)
苹果 (优先级1)

那么出队顺序为梨子 -> 桃子 -> 苹果。
当然,可以在任何时候往优先队列加入元素,而优先队列底层的数据结构堆(heap)会随时调整结构,使得每次的队首元素都是优先级最大的。
1,priority_queue
要使用优先队列,应该添加头文件 queue。 其定义写法也和其他STL容器相同。

priority_queue<typename> name;

2,priority_queue容器内元素的访问
和队列不一样的是,优先对立而没有了front()和back()函数,而只能通过top()函数来访问队首元素,也就是优先级最高的元素。
3,priority_queue常用函数实例解析
(1)push()
push(X)将X入队,时间复杂度O(logN),其中N为当前优先队列中的元素个数。
(2)top()
获取队首(堆顶)的元素。
(3)pop()
使队首(堆顶)的元素出队。
(4)empty()
检测优先队列是否为空。
(5)size()
size()返回优先队列元素的个数。
4,priority_queue内元素优先级的设置
下面来介绍下优先级的设置方法。
(1)基本数据类型的优先级设置
此处指的是int,double,char等可以直接使用的数据类型,对他们的游戏那寄设置一般使数字大的优先级越高,因此队首元素就是优先队列元素中最大的那个(char类型则是字典序最大的)。对基本数据类型来说,下面两种定义是等价的

priority_queue<int> q;
priority_queue<int,vector<int>,less<int>> q;

可以发现,第二种定义方式的尖括号多出了两个参数:一个是vector<int>,另一个是less<int>。其中第二个参数填写的是承载底层数据结构堆的容器,如果第一个参数是double或char型,则此处只需要填写vector<double>或vector<char>;而第三个参数less<int>则是对第一个参数的比较类,less<int>表示数字大的优先级大,而greater<int>表示数字小的优先级大。
(2)结构体的优先级设置
这里以开头举得水果的例子

struct fruit{
	string name;
	int price;
	friend bool operator < (const fruit &f1,const fruit &f2){
		return f1.price < f2.price;
	}
}
priority_queue<fruit> q;   //这里就像sort的cmp函数一样, 这里是正常的 这里是以价格高的水果优先

现在如果希望水果的价格高作为优先级高,就需要重载小于号"<"。重载是指对已有的运算符重新定义。见上代码块。可以看到在结构体增加了一个友元函数。 这里可以记一下, 优先对了的这个函数和sort的cmp函数的效果是相反的。
5,priority_qeue的常见用途
可以解决一些贪心问题,也可以对Dijkstra算法进行优化。

stack的常见用法解析

【简介】stack翻译为栈,是STL种实现一个后进先出的容器。
1,stack的定义
需要添加头文件 stack,用法依然和其他STL容器一样。

stack<typename> name;

2,stack容器内元素的访问
由于stack是一种后进先出的数据结构,在STL的stack只能通过top()来访问栈顶元素。
3,stack常用函数实例解析
(1)push()
将x入栈。
(2)top()
获得栈顶元素。
(3)pop()
弹出栈顶元素。
(4)empty()
判断stack是否为空。
(5)size()
返回stack内元素的个数。
4,stack的常见用途
stack一般用来模拟实现一些递归,防止程序堆栈内存的限制而导致程序运行出错。一般来说,程序的栈内存空间很小。

pair的常见用法解析

【简介】pair是一个很实用的"小玩意",当想要将两个元素绑在一起作为一个合成元素,又不想定义结构体时,可以用pair。其可以看作时一个内部有两个元素的结构体。

struct pair{
	typename1 first;
	typename2 second;
}

1,pair的定义
要使用pair,需要添加头文件 utility。注意:由于map实现过程中设计pair,因此添加map头文件会自动添加 utility头文件,故添加map头文件即可。

pair<typename1,typeName2> name;
pair<string,int> p("haha",5);

如果想初始化,只需要加个括号里面添加初始化的内容即可。如果想要临时构建一个pair,有下面两种方法。

pair<string,int>("haha",5)
make_pair("haha",5)

2,pair中元素的访问
pair中只有两个元素,分别是first和second,只需要按照正常结构体方式去访问即可。
3,pair的使用函数解析
这里只需注意比较操作数,是先比较first,first相等时采取判别second的大小。
4,pair的常见用途

  • 用来代替二元结构体和其构造函数,可以节省编码时间。
  • 作为map的键值来进行插入。

常用的函数

upper_bound() 和 lower_bound()

1.1 lower_bound() 用于二分查找区间内第一个 大于等于某值(>= x) 的迭代器位置
1.2 upper_bound() 用于二分查找区间内第一个 大于某值(> x) 的迭代器位置

ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last, const T& val)
ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last, const T& val)
函数前两个参数分别是已经被排序的序列的起始迭代器位置和结束迭代器位置,将要被查询的范围为[first,last],是一个左闭右开区间的范围,第三个参数则是需要搜寻的元素的值。最后返回查询成功的迭代器的位置。内部逻辑底层实现就是一个二分查找。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值