1.set
set的结构体重载以及内部成员访问。
struct node {
int a,b;
bool friend operator <(node n1,node n2) {
return n1.a < n2.a;
}
};
set<node>nset;
int main() {
for (int i = 0; i < 10; i++)
nset.insert({100-i,i});
for (auto it = nset.begin(); it != nset.end(); it++)
cout << it->a << " " << it->b << endl;
return 0;
}
对于结构体的成员访问需要使用 it->a ,但是对于set<int>这样的容器元素访问,就需要*it。
set<int>iset;
int main() {
for (int i = 0; i < 10; i++)
iset.insert(20 - i);
iset.erase(15); //删除元素
if (iset.find(15) == iset.end())cout << "15 is deleted!" << endl; //查找元素
for (auto it = iset.begin(); it != iset.end(); it++)
cout << *it << endl;
return 0;
}
什么时候用得到set以及其重载:
(1)含负数的不重复统计时使用,如果数据较小且全部为正数时,直接使用数组统计。
(2)结构体查找时使用,经测试,1e6的数据量查找一次几乎不花时间。P.S.结构体查找时lower_bound不可用。
注意:(1)set<int>插入1e5次就需要1.4秒,必然超时,插入1e4次需要138毫秒,最多插入1e4次,而且是单int变量,可见适用范围并不广。
2.lower_bound和upper_bound
用于二分查找,可以查找结构体和元素,可以用普通数组也可以使用vector容器。
头文件:#include <algorithm> 考场上直接一个 #include<bits/stdc++.h>
基本使用格式:
(1) : int pos = lower_bound(begin , end ,value) - begin ;
得到大于等于value的第一个元素的数组下标
(2) : int *pos = lower_bound(begin , end ,value) ;
返回相应元素的指针,可以使用 cout<<*pos ;来输出对应元素
(3) : int *pos = lower_bound(begin , end ,value,greater<type>()) ;
如果数组是从大到小排的,返回第一个小于等于value的数字的一种重载。
(4) : int pos = lower_bound(vector.begin() , vector.end(),value) - vector.begin() ;
可以使用vector容器进行操作,不过这样就需要从头至尾的查找了,数组后面有空的话不可用。
重载结构体的使用格式:
结构体的建立:
struct node{
int year, month, day;
bool friend operator <(node a,node b){
if (a.year != b.year)return a.year < b.year;
else if (a.month != b.month)return a.month < b.month;
else return a.day < b.day;
}
};
vector<node>epoch(100);
结构体初始化及排序:
for (int i = 0; i < 100; i++) {
epoch[i].year = randomInt(1000, 2020);
epoch[i].month = randomInt(1, 12);
epoch[i].day = randomInt(1, 30);
era[i] = epoch[i];
}
sort(epoch.begin(),epoch.end());
打印:
for (int i = 0; i < 100; i++) {
printf("(%d) %d 年 %d 月 %d 日\n",i, epoch[i].year, epoch[i].month, epoch[i].day);
}
开始查找:
node value = { 1946,2,14 };
int pos = lower_bound(epoch.begin(), epoch.end(),value) - epoch.begin();
cout << "pos: " << pos <<" "<< endl;
注意:(1)已经有序的数组,可以是升序或者降序
(2)如果找不到目标,则返回end地址。
(3)upper_bound使用方法同理。
(4)1e7的查找时间依然在10ms一下,可见是非常快的
3.map 和unordered_map
用于键值和值之间的映射关系,以红黑树实现,速度较慢。
头文件:#include<map> #include<unordered_map>
对于一般的 “数字——>任意” 这样的映射关系数组是最佳映射方式,时间为O(1)
使用场景:(1)键值含有负数,不能直接使用数组下标映射的。
(2)字符串作为键值的情景。
(3)用于统计非数字键值个数。
基本使用格式:
声明对象和迭代器
map<string, string>testList;
map<string, string>::iterator it;
map<string, string>::reverse_iterator rit;
unordered_map<string, string>testList2;
unordered_map<string, string>::iterator it2;
正向遍历
for (it = testList.begin(); it != testList.end(); it++)
cout << it->first << " : " << it->second << endl;
逆向遍历
for (rit = testList.rbegin(); rit != testList.rend(); rit++)
cout << rit->first << " : " << rit->second << endl;
对内部成员的访问:
(1)使用迭代器it进行访问,可以对it->second进行赋值和取值,但是对it->first只能进行取值。
(2)可以使用数组形式进行访问,也只是访问testList[keyValue],可以取值也可以赋值,同时可以覆盖插入。
(3)用作统计作用时,如果 testList[keyValue] 为空或者为0,则keyValue这个元素未出现。
(4)insert进行插入时,如果键值已存在是无法进行插入的,也无法覆盖原值,等于啥也没做。
testList.insert(pair<string, string>("keyValue", "secondValue"));
注意:(1) map:1e4的数据插入一遍就需要480ms左右,unordered_map会快一点点,经测试在360ms左右。
(2)遍历速度还是比较快的,1e5 的数据180ms左右。
(3)使用unordered_map时,其内部并不会保持其插入时的顺序,而是根据建树需要给出一个他的顺序。
4.priority_queue
非常好用的数据结构,用堆实现,稳定性强。
头文件:#include<queue> #include<vector> #include<functional>
最后一个头文件用于great<int> ,将堆变为小顶堆。
使用场景:(1)只关注极值的操作过程,比如外部排序每次排出去一个最小的。
(2)哈夫曼编码类问题。
(3)一些队列模拟,比如银行队列,进程调度之类的模拟。
基本是用格式:
默认大顶堆:
priority_queue<int>prique;
小顶堆使用:
priority_queue<int, vector<int>, greater<int> > qi2;
push操作:
for (int i = 0; i < 100; i++) qi2.push(randomInt(1, 1000));
循环pop:
while (!qi2.empty()){ cout<< qi2.top()<<endl ; qi2.pop();}
结构体重载使用priority_queue:
struct node{
int year, month, day;
bool friend operator <(node a,node b){
if (a.year != b.year)return a.year < b.year;
else if (a.month != b.month)return a.month < b.month;
else return a.day < b.day;
}
};
priority_queue<node>epoch;
for (int i = 0; i < 1000; i++)
epoch.push({randomInt(1000,2020),randomInt(1,12) ,randomInt(1,30)});
while (!epoch.empty()){
node tp = epoch.top();
epoch.pop();
cout<< tp.year<<"年"<<tp.month<<"月"<<tp.day<<"日"<<endl ;
}
注意:(1)push操作耗时:1e5的数据量在500ms左右。
(2)pop操作:1e3的耗时在30ms左右,但是到1e4的耗时就达到2秒,所以pop操作不能用太多。