Set(红黑树实现)

set简介:

Set是一种包含已排序对象的关联容器。

set/multiset会根据待定的排序准则,自动将元素排序。两者不同在于前者不允许元素重复,而后者允许。

set的特点:

  1. 不能直接改变元素值,因为那样会打乱原本正确的顺序,要改变元素值必须先删除旧元素,则插入新元素
  2. 不提供直接存取元素的任何操作函数,只能通过迭代器进行间接存取,而且从迭代器角度来看,元素值是常数
  3. 元素比较动作只能用于型别相同的容器(即元素和排序准则必须相同)

只是插入,删除,查找的话,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;
}