写在前面

由于本人实力尚浅,接触算法没多久,写这篇blog仅仅是想要提升自己对算法的理解,如果各位读者发现什么错误,恳请指正,希望和大家一起进步。(●’◡’●)

1.vector

vector

声明

using namespace std;
#include<vector>		//引入头文件
vector<int> a;			//相当于长度动态变化的int数组
vector<int> b[88];		//相当于第一维长88,第二维长度动态变化的int数组(类似于b[88][])
struct rec {};
vector<rec> c;			//自定义的结构体;类型也可以保存在vector中

方法函数

代码含义时间复杂度
c.front()返回第一个数据O(1)
c.pop_back()删除最后一个元素O(1)
c.push_back()在尾部加一个元素O(1)
c.back()返回数组中的最后一个元素O(1)
c.size()返回实际长度O(1)
c.empty()返回一个bool类型,表面vector是否为空O(1)
c.clear()vector清空O(N)
c.begin()返回首元素的迭代器(通常来说是地址)O(1)
c.end()返回最后一个元素后一个位置迭代器(地址)O(1)

说明

  • begin()函数返回指向vector中第一个元素的迭代器。*c.begin()c[0]作用相同。
  • 所有容器都可以视作一个“前开后闭”的结构,返回最后一个元素后一个位置迭代器(地址),即第n个元素再往后的“边界”。c.end()c[n]都是越界访问,使用时要注意。
  • 遍历vector
	for (int i = 0; i < a.size(); i++)		//利用下标遍历		
		cout << a[i] << endl;

	for (vector<int>::iterator p = a.begin(); p != a.end(); p++)		//利用指针遍历
		cout << *p << endl;

2.queue

一种先进先出(FIFO)的数据结构。

声明

using namespace std;
#include<queue>
queue<int> q;
struct rec {}; queue<rec> q;

方法函数

方法含义时间复杂度
push在尾部压入一个元素O(1)
pop删除队头元素(即出队)O(1)
front取出队头元素O(1)
back取出队尾元素O(1)

说明

  • 没什么要说明的,这个数据结构很简单😂
  • 遍历queue
	while (!q.empty())
	{
		cout << q.front() << endl;
		q.pop();
	}

3.priority_queue

就是在正常队列的基础上加了优先级,保证每次的队首元素都是优先级最大的。
它的底层是通过堆来实现的,可以理解为一个大根二叉堆。

声明

#include<queue>
priority_queue<int> q;

方法函数

方法含义时间复杂度
push把元素插入堆 O ( l o g n ) O(log_n) O(logn)
pop删除堆顶元素 O ( l o g n ) O(log_n) O(logn)
top取到堆顶元素O(1)

说明

  • 注意queuepriority_queue取到队头(堆顶)元素的方法不一样。
  • priority_queue也有sizeempty(),只不过在前面的方法里我懒得写

设置优先级

基础数据类型的优先级
priority_queue<int, vector<int>, greater<int>> heap;		//小根堆,每次取出都是队列中最小的元素

参加解释:

  • 第一个参数:就是优先队列中存储的数据类型
  • 第二个参数:vector<int> 是用来承载底层数据结构堆的容器,若优先队列中存放的是double型数据,就要填vector< double >
    总之存的是什么类型的数据,就相应的填写对应类型。同时也要改动第三个参数里面的对应类型。
    至于承载底层数据结构堆的堆,我也没搞明白原理。 大家也没必要去搞明白,会用就可以了。
  • 第三个参数:greater<int>表示数字小的优先级大,堆顶为最小的数字。less<int>则与之相反。
    int代表的是数据类型,也要填优先队列中存储的数据类型
    大家平时使用上面这种写法就可以了,下面的自定义的排序并不推荐
struct cmp1 {
    bool operator()(int x, int y) {
        return x > y;
    }
};
struct cmp2 {
    bool operator()(const int x, const int y) {
        return x < y;
    }
};
priority_queue<int, vector<int>, cmp1> q1; // 小根堆
priority_queue<int, vector<int>, cmp2> q2; // 大根堆

关于设置优先级我在这里就不在赘述了,因为打算法比赛的话基本上掌握最基础的就完全够用了
想要了解更多的—>click here
priority_	queue

4.deque

双端队列是一个支持在两端高效插入或者删除元素的连续线性存储空间。
它就像是vectorqueue的结合。

声明

#include<deque>
deque<int> dq;

方法函数

方法含义时间复杂度
begin()/end()deque 的头/尾迭代器(地址)O(1)
front()/back()队头/队尾元素O(1)
push_back()/push_front()将元素插入队尾/队头O(1)
pop_back()/pop_front()删除队尾/队头元素O(1)
[]随机访问O(1)

5.set

set容器里的元素不会重复(multiset可以包含若干个相同的元素),当插入集合中已有的元素时,并不会插入进去,而且set容器里的元素自动从小到大排序。内部实现是一颗红黑树(平衡树的一种)
总的来说set里面的元素不重复 且有序

声明

#include<set>
set<int> s;
struct rec {}; set<rec> s;

方法函数

方法含义时间复杂度
size()/empty()/clear()分别为元素个数,是否为空,清空O(1)
find()查找某一元素,有则返回该元素对应的迭代器,无则返回结束迭代器
count()查找set中某一元素出现的次数,由于set元素唯一,相当于查询元素是否出现
begin()/end()和前面的容器的一样O(1)

由于set在算法比赛中使用的频次非常低(仅仅是根据我的个人理解,不对勿喷),所以这里我就只是简单介绍一下set,不做赘述。

6.map

map容器是一个键值对key-value的映射(映射类似于函数的对应关系,每一个x对应一个y),map中每个键对应一个值,和python中的字典非常相似。

声明

//头文件
#include<map>
//初始化定义
map<string, string> mp;
map<string, int> mp;
map<int, node> mp;//node是结构体类型

方法函数

方法含义
size()/empty)/begin()/end()和前面的容器一样
insert()插入元素,要以键值对形式插入
[][]里面是key,返回的是value
find()返回键为key的映射的二元组的迭代器 O ( l o g N ) O(log_N) O(logN)注意:用find函数来定位数据出现位置,它返回一个迭代器。当数据存在时,返回数据所在位置的迭代器,数据不存在时,返回mp.end()

说明

  • 使用mp.find(),mp.count(),mp[]key]均可以查找元素是否存在。
  • []操作符是map中最吸引人的地方,我们可以通过mp[key]来得到key对应的value,还可以对mp[key]进行赋值操作,改变对应key对应的value
  • 但是,若查找的key不存在时,mp会自动创建一个二元组(key,zero),返回zero的引用。这里的zero表示一个广义的“零值”,如整数0,空字符串等。如果查找之后不对其赋值,长时间下来就产生许多无用的零值二元组,白白占用空间降低程序运行效率,建议使用[]前先用find查询一下。
  • map特性:map会按照键的顺序从小到大自动排序,键的类型必须可以比较大小
  • 还有unordered_map,内部用哈希表实现,内部元素杂乱无章,但其实我觉得二者没什么大的区别,算法比赛中都可以使用。

7.stack

一种先进后出(FILO)的数据结构

声明

//头文件需要添加
#include<stack>

//声明
stack<int> s;
stack<string> s;
stack<node> s;//node是结构体类型

方法函数

方法含义时间复杂度
empty()/size()和前面的容器一样O(1)
top()取得栈顶元素(但是不删除)O(1)
push()将元素入栈O(1)
pop()移除栈顶元素O(1)

说明

  • 一般来说可以用一个数组来进行模拟,一个存放下标的变量top模拟指向栈顶的指针。
  • 还有单调栈的写法可以使用额外变量tthh来模拟,具体等我再写一篇关于单调栈的blog

8.pair

pair只含有两个元素,可以看作是只有两个元素的结构体。

pair<int, int> a;
pair<int, string> b;

应用

  • 代替二元结构体
  • 作为map的键值对进行插入

访问

p.first访问第一个元素,p.second访问第二个元素

//定义结构体数组
pair<int,int> p[20];
for(int i = 0; i < 20; i++) {
    //和结构体类似,first代表第一个元素,second代表第二个元素
    cout << p[i].first << " " << p[i].second;
}

string

string是一个字符串类,和char型字符串类似。和char[N]非常相似

声明

//头文件
#include<string>

//1.
string str1; //生成空字符串

//2.
string str2("123456789"); //生成"1234456789"的复制品 

//3.
string str3("12345", 0, 3);//结果为"123" ,从0位置开始,长度为3

//4.
string str4("123456", 5); //结果为"12345" ,长度为5

//5.
string str5(5, '2'); //结果为"22222" ,构造5个字符'2'连接而成的字符串

//6.
string str6(str2, 2); //结果为"3456789",截取第三个元素(2对应第三位)到最后

读入详解

  • 读入字符串,遇到空格,回车结束
string s;
cin >> s;
  • 读入一行字符串(包括空格),遇到回车结束
string s;
getline(cin, s);

注意:getline(cin,s)会获取前一个输入的换行符,需要在前面添加读取换行符的语句,如getchar(),下面是示例

int n;
string s;
cin >> n;
getchar(); //cin.get()
getline(cin, s);//可正确读入下一行的输入
  • cin和cout解锁
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);

为什么要进行cincout解锁
在一些题目中,读入的数据量很大,往往超过了1e5(105)的数据量,而cincout的读入输出的速度很慢(是因为cincout为了兼容C语言的读入输出在性能上做了妥协),远不如scanfprintf的速度,具体原因可以搜索相关的博客进行了解。
所以对cincout进行解锁使cincout的速度几乎接近scanfprintf,避免输入输出超时。
注意:cin cout解锁使用时,不能与 scanf,getchar, printf,cin.getline()混用,一定要注意,会出错。

感谢各位童鞋看到这里,这篇blog我还没有写完,几天后还会更新STL函数赶紧关注一波后面我会持续更新数据结构与算法,也希望大家点点赞,我们一起进步(❁´◡`❁)

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐