1.#include<vector>
vector是变长数组,支持随机访问,不支持在任意位置O(1)插入。
为了保证效率,元素的增删一般应该在末尾进行。
1.1定义vector
vector<int>a; //相当于一个长度动态变化的int数组
vector<int>b[233]; //相当于第一维长233(静态),第二维长度动态变化的int数组
struct rec{ };
vector<rec> c; //自定义的结构体类型保存在vector中
1.2相关函数
1.2.1size/empty
size函数返回vector的实际长度(包含的元素个数),empty函数返回一个bool类型,表示vector是否为空。二者的时间复杂度都是O(1)。
所有的STL容器都支持这两个函数,含义相同。
1.2.2clear
clear函数把vector清空
除了栈,队列,优先队列之外,其他所有STL容器都有clear函数
1.2.3 迭代器
类似于指针,用星号“ * ”操作符解除引用。
可以把vector的迭代器与一个整数相加减,与指针类似,得到两个迭代器对应下标之间的距离
//一个保存int的vector的迭代器声明
vector<int>::iterator it = a.begin();//a的起始迭代器,a的第一个元素地址
//支持相加减
it + 2;//相当于访问a[2]
it; //相当于访问a[0]
*it;//取迭代器值
1.2.4 begin/end
begin函数返回指向vector中第一个元素的迭代器。
【例】:a是一个非空的vector,则*a.begin()与 a[0] 的作用相同
所有的容器都可以视作一个“前闭后开”的结构,
end函数返回vector的尾部,即第n个元素再往后的 “边界” 。
*a.end() 与a[n]都是越界访问,其中 n = a.size()
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> a({1,2,3)};//初始化vector,包含1,2,3
vector<int> b[233];
a.size();
a.empty();
a.clear();
vector<int>::iterator it = a.begin(); //第一个元素
a.end(); //最后一个元素的后一个
//结构体类型
struct Rec
{
int x,y;
};
vestor<Rec> c;//自定义的结构体类型也可以保存在vector
}
1.2.5 遍历vector<int>a
三种遍历方式
vector<int> a({1,2,3}); //方法一 for(int i=0;i<a.size();i++) cout<<a[i]<<' '; cout<<endl; //方法二 for(auto i=a.begin();i!=a.end();i++)//auto即指vector<int>::iterator cout<<*i<<' '; cout<<endl; //方法三 for(int x : a) cout<<x<<' ';
vector<int>::iterator i 可以换成 auto i
绝大多数不会有vector访问迭代器,太麻烦!
1.2.6.front/back
front()函数返回vector的第一个元素,等价于 *a.begin() 和 a[0]
back() 函数返回vector的最后一个元素,等价于 *==a.end() 和 a[a.size()-1]
如下:
1 2 3
| | | |
front back end
【具体实例】:
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> a({1,2,3});//初始化
cout<<a.front()<<' ' <<a[0]<<' '<<*a.begin()<<endl;//返回vector的第一个元素
cout<<a.back()<<' '<<a[a.size()-1]<<endl;//返回最后一个元素
return 0;
}
输出:1 1 1
3 3
1.2.7.push_back / pop_back
a.push_back(x) 把元素x插入vector a的尾部
b.pop_back() 删除vector a的最后一个元素
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> a({1,2,3});//初始化
a.push_back(4);//在最后插入4
for(auto x : a) cout<<x<<' ';
cout<<endl;
a.pop_back();//删掉最后一个元素
a.pop_back();
for(auto x : a) cout<<x<<' ';
cout<<endl;
return 0;
}
输出:1 2 3 4
1 2
2.队列 #include<queue>
头文件queue主要包括循环队列 queue ——先进先出(普通队列就是循环队列) 、优先队列 priority_queue(优先往外弹最大值)两个容器
声明:
queue<int> q; //int可以换其他类型
struct rec {...} ; //用大根堆结构体rec中必须定义小于号,小根堆重载大于号
queue<rec> q; //定义结构体的队列
优先队列
- priority_queue<int> q; //大根堆
- priority_queue<int,vector<int>,greater<int> q; //小根堆
- priority_queue<pair <int,int> >q; //pair是一个二元组
循环队列 queue —— 长度与该队列现存的元素相关,与插入的无关
push 从队尾插入
pop 从队头插入
front 返回队头元素
back 返回队尾元素
优先队列 priority_queue
push 把元素插入堆
pop 删除堆顶元素
top 查询堆顶元素(最大值)
【循环队列的实现】:
#include<iostream> #include<vector> #include<queue> using namespace std; int main() { //循环队列 queue<int> q; queue<double> a; struct rec { int a,x,y; }; queue<rec> b; }
循环队列、优先队列的操作以及实现小根堆:
#include<iostream> #include<vector> #include<queue> using namespace std; int main() { queue<int> q; //队列 //普通队列操作 q.push(1); //在对头插入一个元素 q.pop(); //弹出队尾元素 q.front(); //返回对头 cout<<q.back()<<endl; //返回队尾元素 q=queue<int>();//初始化队列 priority_queue<int> a; //大根堆 //优先队列操作 a.push(1); //插入一个数 a.top(); //取最大值 a.pop(): //删除最大值 priority_queue<int,vector<int>,greater<int> >b; //小根堆 struct Rec { int a,b; bool operator > (const Rec& t) const { return a>t.a; } }; priority_queue<Rec,vector<Rec>,greater<Rec> > d; d.push({1,2}); }
队列没有clear函数,清空队列——初始化即可;q=queue<int>();
3.#include<stack>栈
头文件stack包含栈。声明与前面的容器类似。
push 向栈顶插入
pop 弹出栈顶元素
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
int main()
{
stack<int> stk;
stk.push(1);//栈顶插入1
stk.top();//取栈顶元素——1
stk.pop();//弹出栈顶元素
}
4.#include<deque>双端队列
支持随机存储。双端队列deque是一个支持在两端高效插入或者删除元素的连续线性存储空间。它就像是vector(单端数组)和queue(双端数组)的结合。与vector相比,deque在头部、结尾增删元素仅需要O(1)的时间;与queue相比,deque像数组一样支持随机访问。
vector在结尾插入、删除O(1);在开头插入、删除O(n)。
[ ] 随机访问
begin. / end. 返回deque的头/尾迭代器
front / back 队头 / 队尾元素
push_back 队尾入队
push_front 队头入队
pop_back 队尾出队
pop_front 队头出队
clear 清空队列
#include<iostream>
#include<deque>
//#include<vector>
using namespace std;
int main()
{
deque<int> a;
a.begin(), a.end();
a.front(), a.back();
a.push_back(1), a.push_front(2);
a[0];//随机访问元素
a.pop_back();//弹出最后一个元素
a.pop_front();//弹出第一个元素
a.clear();//清空
}
5.#include<set>
头文件set主要包括set和multiset两个容器,分别是 “有序集合” 和 “有序多重集合”,即前者的元素不能重复,而后者可以包含若干个相等的元素。set 和 multiset 的内部实现是一棵红黑树,他们支持的函数基本相同。
声明:
set<int> s; struct ret{...};//结构体rec中必须定义小于号 multiset<double> s;
size / empty / clear 与 vector类似
5.2迭代器
set 和 multiset 的迭代器称为“双向访问迭代器” ,不支持随机访问,支持星号(*)解除引用,仅支持 “++” 和 “--” 两个与算术相关的操作。
设 it 是一个迭代器,例如set<int> ::iterator it;
若把 it++ ,则it会指向下一个元素——这里的下一个元素指的是元素从小到大排序的结果中,排在it下一名的元素。同理,若 it-- ,则it 将会指向排在“上一名”的元素。
5.3函数
begin / end ——返回集合的首尾迭代器
时间复杂度均为O(1)。
s.begin() 指向集合中最小元素的迭代器。
s.end() 指向集合中最大元素的下一个位置的迭代器。--s.end() 是指向集合中最大元素的迭代器 就像vector一样前闭后开
s.insert(x) 把一个元素x插入到集合s中,时间复杂度为O(log n)。在set中,若元素已存在,则不会重复插入该元素,对集合的状态无影响。
s.find(x) 在集合s中查找等于x的元素,并返回指向该元素的迭代器。若不存在,则返回s.end().时间复杂度为O(log n).
lower_bound / upper_bound 这两个函数的用法与find类似,但查找的条件略有不同,时间复杂度为O(long n)。
s.lower_bound(x) 查找大于等于x的元素中最小的一个,并返回指向该元素的迭代器。
s.upper_bound(x) 查找大于x的元素中最小的一个,并返回指向该元素的迭代器。
erase()——设it是一个迭代器,s.erase(it) 从 s 中删除迭代器 it 指向的元素,时间复杂度为O(log n)。 设x是一个元素,s.erase(x) 从 s 中删除所有等于x的元素,时间复杂度为O(k+log n).其中k是被删除的元素个数。
count——s.count(x) 返回集合s中等于x的元素个数,时间复杂度为O(k+log n),其中k为元素x的个数。
【完整示例】:
#include<iostream>
//set
#include<set>//有两种容器
using namespace std;
int main()
{
set<int> a;//元素不能重复
multiset<int> b;//元素可以重复
set<int>::iterator it = a.begin();
it++;it--;
++it; --it;
a.end();
a.insert(x);
if(a.find(x) == a.end()) //判断x在a中是否存在
a.lower_bound(x);//找到大于等于x的最小元素的迭代器
a.upper_bound(x);//找到大于x的最小元素的迭代器
a.erase(x);//把x的所有迭代器删掉
a.count(x);//x在a里面存在的个数,因为set不能重复,所有a存在x返回1,不存在返回0
struct Rec
{
int x, y;
bool operator< (const Rec& t) const
{
return x < t.x;
}
};
set<Rec> c;
}
6.#include<map>——映射
map容器是一个键值对key-value的映射,其内部实现是一颗以key为关键词的红黑树。map的key和value可以是任意类型,其中key必须定义小于号运算符。
6.1声明:
map<key_type,value_type>name;
例如:
map<long,long,bool> vis;
map<string,int> hash;
map<pair<int,int>,vector<int> >test;
size / empty / clear / begin / end 均与set类似
6.2 函数
insert / erase——与set类似,但其参数均是pair<key_type,value_type>
find—— h.find(x) 在变量名为h的map 中查找key为x的二元组。不能做输出!
[ ] 操作符—— h[key] 返回key映射的value的引用,时间复杂度为O(log n)。
[ ]操作数是map最吸引人的地方。我们可以很方便地通过h[key] 来得到 key 对应的value. 还可以对 h[key] 进行赋值操作,改变key 对应的value。
#include<iostream>
#include<map>
using namespace std;
int main()
{
map<string,int> a;//存的是二元组
a["hha"]= 2;
cout<<a["hha"]<<endl;
}
输出:2
int main()
{
map<string,vector<int>> a;//存的是二元组
a.insert({"a",{} });//插入
a["hha"]= vector<int>({1,2,3,4});
cout<<a["hha"][2]<<endl;
cout<< (a.find("hha") == a.end() ) <<endl;//判断是不是等于end
}
输出:3
0
7.#include<unordered_set> / #include<unordered_map>
无序的,但是效率更高
#include<iostream>
#include<unordered_set>
#include<unordered_map>
using namespace std;
int main()
{
unordered_set<int> S;//底层实现哈希表,与set类似,无序的,不能存储重复元素
unordered_multiset<int> b;//哈希表,可以存储重复元素
unordered_map<int,int> c;//与map类似,效率更高,O(1)
}
8.#include<bitset>——位运算用
可以定义二进制的串
#include<iostream>
#include<bitset>
using namespace std;
int main()
{
bitset<1000> a,b;//定义长度1000的二进制数组a
a[0] = 1;
a[1] = 1;
a.set(3);//把第三位设置成1
a.reset(3);//把第三位设置成0
cout<<a[2]<<endl;//未定义的都是0;
cout<<a.count<<endl;//返回1的个数
}
输出:0
1
pair的使用:
pair<int,string> a;
a={3,"haha"};
cout<<a.first<<' '<<a.second<<endl;//输出第一第二个值