Set(红黑树实现)
set简介:
Set是一种包含已排序对象的关联容器。
set/multiset会根据待定的排序准则,自动将元素排序。两者不同在于前者不允许元素重复,而后者允许。
set的特点:
- 不能直接改变元素值,因为那样会打乱原本正确的顺序,要改变元素值必须先删除旧元素,则插入新元素
- 不提供直接存取元素的任何操作函数,只能通过迭代器进行间接存取,而且从迭代器角度来看,元素值是常数
- 元素比较动作只能用于型别相同的容器(即元素和排序准则必须相同)
只是插入,删除,查找的话,set / map在c++ 11引入unordered_set / unordered_map后这方面意义就不大了。。。但set由于是红黑树实现,可以保证内部元素的有序,可以提供对数复杂度下集合内最接近给定值的的元素,或者快速输出top k大等。。。
set中每个元素只包含一个关键字:set支持高效的关键字查询操作----检查一个给定关键字是否在set中(find函数,复杂度lgN)。集合set和数学上的集合是一致的,每个元素最多只出现一次,并且是排好序的,和sort一样,自定义类型也可以构造set,但同样必须定义<运算符。
set的底层实现:红黑树
为什么不用hash?
首先set,不像map那样是key-value对,它的key与value是相同的。关于set有两种说法,第一个是STL中的set,用的是红黑树;第二个是hash_set,底层用得是hash table。红黑树与hash table最大的不同是,红黑树是有序结构,而hash table不是。但不是说set就不能用hash,如果只是判断set中的元素是否存在,那么hash显然更合适,因为set 的访问操作时间复杂度是log(N)的,而使用hash底层实现的hash_set是近似O(1)的。然而,set应该更加被强调理解为“集合”,而集合所涉及的操作并、交、差等,即STL提供的如交集set_intersection()、并集set_union()、差集set_difference()和对称差集set_symmetric_difference在。(),都需要进行大量的比较工作,那么使用底层是有序结构的红黑树就十分恰当了,这也是其相对hash结构的优势所
常用操作:
begin(); // 返回指向第一个元素的迭代器
end(); // 返回指向最后一个元素的迭代器
clear(); // 清除所有元素
count(); // 返回某个值元素的个数
empty(); // 如果集合为空,返回true
equal_range(); //返回集合中与给定值相等的上下限的两个迭代器
erase()–删除集合中的元素
find()–返回一个指向被查找到元素的迭代器
get_allocator()–返回集合的分配器
insert()–在集合中插入元素
lower_bound()–返回指向大于(或等于)某值的第一个元素的迭代器
key_comp()–返回一个用于元素间值比较的函数
max_size()–返回集合能容纳的元素的最大限值
rbegin()–返回指向集合中最后一个元素的反向迭代器
rend()–返回指向集合中第一个元素的反向迭代器
size()–集合中元素的数目
swap()–交换两个集合变量
upper_bound()–返回大于某个值元素的迭代器
value_comp()–返回一个用于比较元素间的值的函数
自定义set:
set<int,greater<int> > a;//从大到小排序
自定义结构:
struct Info
{
string name;
float score;
//重载“<”操作符,自定义排序规则
bool operator < (const Info &a) const
{
//按score从大到小排列
return a.score<score;
}
}
set<Info> s;
......
set<Info>::iterator it;
应用:
去重–简单的插入,迭代器遍历,统计函数
#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
set<int,greater<int> > a;
int main(){
a.insert(2);
a.insert(0);
a.erase(2);
a.insert(110);
set<int,greater<int> >::iterator it;
for (it=a.begin(); it!=a.end(); it++){
cout<<*it<<" ";
}
cout<<a.count(11)<<endl;
}
给vector去重,assign函数
#include<set>
#include<vector>
#include<iostream>
using namespace std;
int main(){
vector<int> vec;
vec.push_back(5);
vec.push_back(6);
vec.push_back(2);
vec.push_back(3);
vec.push_back(1);
set<int> st(vec.begin(), vec.end());
vec.assign(st.begin(), st.end());
vector<int>::iterator it;
for (it = vec.begin(); it != vec.end(); it++)
cout << *it<<endl;
return 0;
}