优先队列
1.可以插入一个数值。复杂度:对每个元素,插入和删除只是修改了堆顶和堆底,不需要所有的都排序,只是需要再次调整好堆,因此时间复杂度都是O(logN)
常用格式:
priority_queue q;
//node是一个结构体
//结构体里重载了‘<’小于符号
priority_queue ,greater > q;
//不需要#include头文件
//注意后面两个“>”不要写在一起,“>>”是右移运算符
priority_queue ,less >q; //less是从大到小,greater是从小到大
基本操作(以q为例):
q.size();//返回q里元素个数
q.empty();//返回q是否为空,空则返回1,否则返回0
q.push(k);//在q的末尾插入k
q.pop();//删掉q的第一个元素
q.top();//返回q的第一个元素
q.back();//返回q的末尾元素
struct node
{
int x,y;
bool operator < (const node & a) const
{
return x
这个node结构体有两个成员,x和y,它的小于规则是x小者小, 它是按照重载后的小于规则,从大到小排序的。
参考:http://blog.csdn.net/c20182030/article/details/70757660
练题 : PKU3253 POJ2431
二叉搜索树
可以进行如下操作的数据结构:1.插入一个数值 2.查询是否包含某个数值 3.删除某个数值
操作的复杂度:不论哪一种操作,其复杂度均与树的高度有关,故设其有n个元素,则平均每次操作需要O(logn)时间复杂度。
在STL中的操作:set(使用二叉搜索树维护的集合的容器) map(维护键和键对应的数值的容器)
SET
set,顾名思义是“集合”的意思,在set中元素都是唯一的,而且默认情况下会对元素自动进行升序排列
set容器的常用操作
使用时注意包含头文件 std::set and std::multiset associative containers
s.begin() 返回set容器的第一个元素,迭代器指向二叉搜索树最左边的结点
s.end() 返回set容器的最后一个元素,迭代器指向二叉搜索树最右边的结点
s.clear() 删除set容器中的所有的元素
s.empty() 判断set容器是否为空
s.insert() 插入一个元素
s.erase() 删除一个元素,参数可为元素或指定位置的迭代器,功能不同
s.size() 返回当前set容器中的元素个数
set容器的创建
#include
#include
#include
using namespace std;
set s;
int main(){
set seta; //默认是小于比较器less的set
set > setb; //创建一个带大于比较器的set,需包含头文件functional
int a[5] = {1,2,3,4,5};
set setc(a,a+5); //数组a初始化一个set;
set setd(setc.begin(),setc.end()); //setc初始化一个set
//上述两例均为区间初始化
set sete(setd); //拷贝构造创建set
return 0;
}
删除过程
如何删除某位置元素:http://blog.csdn.net/qq_36509464/article/details/52994182
查找
s.find() 查找一个元素,如果容器中不存在该元素,返回值等于s.end()
STL常用的其他操作
s.lower_bound() 返回第一个大于或等于给定关键值的元素
s.upper_bound() 返回第一个大于给定关键值的元素
s.equal_range() 返回一对定位器,分别表示 第一个大于或等于给定关键值的元素 和 第一个大于给定关键值
的元素,这个返回值是一个pair类型,如果这一对定位器中哪个返回失败,就会等于
s.end()
自定义比较函数
#include
#include
#include
using namespace std;
struct cmp{
bool operator () (const int &a, const int &b){
return a > b;
}
};
sets; //自定义排序函数构造set
void setprint(int cnt){
cout << "Test output :" << cnt << ":" << endl;
for(set::iterator it = s.begin(); it!= s.end(); it++)
cout << *it << " ";
puts("");
return ;
}
int main(){
s.insert(1);
s.insert(2);
s.insert(6);
setprint(1); // 6 2 1
return 0;
}
至于求并、交、差、对称差等操作,暂不细说,使用时要包含头文件”algorithm”。
可以存放重复键值的则为multiset,还有此外还有unordered_set和unordered_multiset,为set和multiset的无序版,使用时要包含头文件”unordered_set”。
头文件:#include
map技术的原理:将键值和对应数据封装成一个结构对象,并将此对象插入到红黑树,完成一个元素的添加。同时,也要提供一个仅使用键值进行比较的函数对象,将它传递给红黑树。由此,就可利用红黑树的操作,将map元素数据插入到二叉树中的正确位置,也可以根据键值进行元素的删除和检索。map提供了一对一的数据检索功能,每个键值只能在map中出现一次。
最基本的map的构造方法:map
2.数据的插入
在构造map容器后,我们就可以往里面插入数据了。这里讲两种简单实用的插入数据的方法:
第一种:用insert函数插入pair数据,下面举例说明(以下代码虽然是随手写的,应该可以在VC和GCC下编译通过,大家可以运行下看什么效果,在VC下请加入这条语句,屏蔽4786警告 #pragma warning (disable:4786) )
#include
第二种. 用数组方式插入数据
#include
两种插入方法的不同:用insert函数插入数据,在数据的插入上涉及到集合的唯一性这个概念,即当map中有这个关键字时,insert操作是插入数据不了的,但是用数组方式就不同了,它可以覆盖以前该关键字对应的值。
3.map中数据的查找
下面介绍三种用以在map中查找数据的方法
第一种:用count函数来判定关键字是否出现,其缺点是无法定位数据出现位置,由于map的特性,一对一的映射关系,就决定了count函数的返回值只有两个,要么是0,要么是1,出现的情况,当然是返回1了。
第二种:用find函数来定位数据出现位置,它返回的一个迭代器,当数据出现时,它返回数据所在位置的迭代器,如果map中没有要查找的数据,它返回的迭代器等于end函数返回的迭代器
#include
第三种:使用lower_bound()和upper_bound函数()所分别返回的值来确定数据是否存在。
lower_bound函数用法,这个函数用来返回要查找关键字的下界(是一个迭代器)
upper_bound函数用法,这个函数用来返回要查找关键字的上界(是一个迭代器)
"前闭后开"是STL容器的设计原则,lower_bound(v)可以理解为[v, inf)范围内的第一个元素。而upper_bound(v)则可以理解为(-inf, v]的最后一个元素。
所以[lower_bound(v), upper_bound(v) )这个前闭后开区间恰好就是所有的v构成的区间。
4.数据的清空与判空
清空map中的数据可以用clear()函数,判定map中是否有数据可以用empty()函数,它返回true则说明是空map
5.数据的删除
这里要用到eraser函数,注意:STL中的区间均为前闭后开的区间
#include
6.其他一些函数用法
这里有swap,key_comp,value_comp,get_allocator等函数,感觉到这些函数在编程用的不是很多,略过不表,有兴趣的话可以自个研究
7.关于排序
这里要讲的是一点比较高深的用法了,排序问题,STL中默认是采用小于号来排序的,以上代码在排序上是不存在任何问题的,因为上面的关键字是int型,它本身支持小于号运算,在一些特殊情况,比如关键字是一个结构体,涉及到排序就会出现问题,因为它没有小于号操作,insert等函数在编译的时候过不去,下面给出两个方法解决这个问题
第一种:重载小于号,如下:
Typedef struct tagStudentInfo
{
Int nID;
String strName;
Bool operator < (tagStudentInfo const& _A) const
{
//这个函数指定排序策略,按nID排序,如果nID相等的话,按strName排序
If(nID < _A.nID) return true;
If(nID == _A.nID) return strName.compare(_A.strName) < 0;
Return false;
}
}StudentInfo, *PStudentInfo; //学生信息
第二种:仿函数的应用,这个时候结构体中没有直接的小于号重载,程序说明
#include
8.outro
由于STL是一个统一的整体,map的很多用法都和STL中其它的东西结合在一起,比如在排序上,这里默认用的是小于号,即less<>,如果要从大到小排序呢,这里涉及到的东西很多,在此无法一一加以说明。
还要说明的是,map中由于它内部有序,由红黑树保证,因此很多函数执行的时间复杂度都是log2N的,如果用map函数可以实现的功能,而STL Algorithm也可以完成该功能,建议用map自带函数,效率高一些。
另外在空间方面:由于map的每个数据对应红黑树上的一个节点,这个节点在不保存你的数据时,是占用16个字节的,一个父节点指针,左右孩子指针,还有一个枚举值(标示红黑的,相当于平衡二叉树中的平衡因子)。
lista{1,2,3}
lista(n) //声明一个n个元素的列表,每个元素都是0
lista(n, m) //声明一个n个元素的列表,每个元素都是m
lista(first, last) //声明一个列表,其元素的初始值来源于由区间所指定的序列中的元素,first和last是迭代器
2.begin()与end()
判空
5.reisize()
调用resize(n)将list的长度改为只容纳n个元素,超出的元素将被删除。如果n比list原来的长度长,那么默认超出的部分元素置为0。也可以用resize(n, m)的方式将超出的部分赋值为m。
listb{1, 2, 3, 4};
b.resize(2);
list中输出元素:1,2
listb{1, 2, 3, 4};
b.resize(6);
list中输出元素:1,2,3,4,0,0
listb{1, 2, 3, 4};
b.resize(6,9);
list中输出元素:1,2,3,4,9,9
6.clear() 7.front()和back() 8.pop_back()和pop_front()
9.assign()
有两种使用情况: (1) a.assign(n,val)将a所有的元素替换为n个val元素.
listb{1,2,3,4,5};
b.assign(5,10); //b中的元素变为10,10,10,10,10
(2)a.assign(b.begin(),b.end())
lista{6,7,8,9};
listb{1,2,3,4,5};
b.assign(a.begin(),a.end());
10.swap
11.reserve()实现逆置
12.merge()
c1.merge(c2) 合并两个有序的链使其有序放到c1之中 并释放c2
c1.merge(c2,comp) 合并2个有序的链表并使之按照自定义规则排序之后从新放到c1中,释放c2。
a.merge(b) 调用结束后b变为空,a中元素包含原来a和b的元素。
当源list均有序时,得到的list仍是有序的。
当源list无序时,得到的list不能保证有序,之所以这样说是因为,当list1的前两个元素即表现出无序时,合并后的结果将是直接把list2接到list1的后面。
13.splice()
list::splice实现list拼接的功能。将源list的内容部分或全部元素删除,拼插入到目的list
a.splice(a.begin(),b) 将b连接到a的begin位置,并释放c2
a.splice(a.begin(),b,b.begin() ) 将b的begin位置的元素连接到a的begin位置的元素,并释放b的begin位置的元素
a.splice(a.begin(), b,b.begin(),b.end() ) 将b的[begin,end)位置的元素连接到a.begin()位置的元素,并释放b的[begin,end)位置的元素
14.insert()
在指定位置插入一个或多个元素
a.insert(a.begin(),100); //在a的开始位置(即头部)插入100
a.insert(a.begin(),2, 100); //在a的开始位置插入2个100
a.insert(a.begin(),b.begin(), b.end());//在a的开始位置插入b从开始到结束的所有位置的元素
15.erase()
删除一个或一个区域的元素 a.remove(a.begin(),a.end() )
16.remove()
删除所有指定值的元素 a.remove(x);
remove_if(comp) 删除满足条件的元素,参数为自定义的回调函数
class single_digit{
public:
bool operator()(const int& value){
return (value<10);
}
};
int main(){
list a{6,7,4,9,7,10};
a.remove_if(single_digit());
list::iterator it = a.begin();
while(it != a.end()){
cout<<*it<<" ";
it++;
}
return 0;
} //输出为0