STL Set、Multiset
参考文章: https://blog.csdn.net/weixin_45389639/article/details/121618243
- set/multiset以rb_tree为底层结构,因此有元素自动排序的功能,排序的依据是key,而set/multiset元素的value和key合一(Value就是Key)。
- 注意:我们无法使用set/multiset的iterator改变元素值(因为key有其严谨的排列规则)。set/multiset的iterator是其底部rbtree的const-iterator。
- set的insert()用的是rb_tree的inset_unique()。
- multiset的insert()用的是rb_tree 的inset_equal()。
set定义
template<class Key,
class Compare = less<Key>,
class Alloc = alloc>
class set {
public:
typedef Key key_type;
typedef Key value_type;
typedef Compare key_compare;
typedef Compare value_compare;
private:
typedef rb_tree <key_type,
value_type,
identity<value_type>,
key_compare,
Alloc> rep_type;
rep_type t; // 内部rb_tree容器
public:
//迭代器,set不可以通过迭代器修改元素
typedef typename rep_type::const_iterator iterator;
};
set中所有操作,使用红黑树做,set这里可以看成一个container adapter
map multimap
map与set区别,set中 key=value
map元素分为key和data,组合起来是value
Map/multimap以rb_tree为底层结构,因此有元素自动排序的功能,排序的依据是key。
注意:我们无法使用map/multimap的iterator改变元素值(因为key有其严谨的排列规则),但可以用它来该改变元素的data。map/multimap内部自动将user指定的keytype设定为const,以便禁止user对元素的key赋值。
- map的insert()用的是rb_tree的inset_unique()。
- multimap的insert()用的是rb_tree 的inset_equal()。
template<class key,Class T,class Compare=less<key>,class Alloc=alloc>
class map{
public:
typedef key key_type;
typedef T data_type;
typedef T mapped_type;
typedef pair<const key,T> value_type // 这里指定const key防止user修改key
typedef Compare key_compare;
private:
typedef rb_tree<key_type,value_type,select1st<value_type>,key_compare,Alloc> rep_type
rep_type t; //rb_tree
public:
typedef typename rep_type::iterator iterator;
}
template<class Pair>
struct select1st:public unary_function<Pair,typename Pair::first_type>
{
const typename Pair::first_type& operator()(const Pair& x){
return x.first;
}
}
map中特别的符号重载operator[]
operator[](const key_type& _k)
如果k存在,返回该iterator,不存在就在合适的位置创造该k
mapped_type& operator[](const key_type& _k){
iterator _i = lower_bound(_k);
if(_i=end()||key_comp()(_k,(*_i).first))
_i = insert(_i,value_type(_k,mapped_type()));
return(*_i).second;
}
hashtable
当元素个数大于buckets时,进行rehashing。成长倍数(在GNUC下)为两倍,成长完成后所有元素重新排列,实现元素的散列分布。
GUNC选择质数作为篮子大小, 每次两倍扩充,使用扩充后附近的质数作为篮子大小
hashtable代码
//HashFcn 确定Hashtable中元素编号的方法,通常为函数对象(将存入对象转为编号)
//Extractkey 如果元素是一对pair,需要告诉提取key的方法
//Equalkey 比较key大小的方法
template<class value,
class key,
class HashFcn,
class Extrackey,
class EqualKey,
class Alloc=alloc>
class hashtable{
public:
typedef HashFnc hasher;
typedef EqualKey key_equal;
typedef size_t size_type;
private:
hasher hash;
key_equal equals;
Extrackey get_key;
typedef _hashtable_node<value> node;
vector<node*,Alloc> buckets;
size_type num_elements;
public:
size_type bucket_count()const{return buckets.size();}
...
}
template<class value>
struct _hashtable_node{
_hashtable_node* next;
value val;
...
}
template<class value,class key,class HashFcn,class Extrackey,class EqualKey,class Alloc=alloc>
struct _hashtable_iterator{
...
node* cur;
hashtable* ht;
}
void hashtableTest(){
hashtable<const char*,
const char*,
hash<const char*>,
identity<const char*>,
eqstr>
ht(50,hash<const char*>(),eqstr());
ht.insert_unique("zsas");
ht.insert_unique("asdfs");
}
struct eqstr{
bool operator()(const char*s1,const char*s2)const{
return strcmp(s1,s2)==0;
}
}
怎样使用hashfunction?
hashfun源码:
template<class key>struct hash{};
_STL_TEMPLATE_NULL struct hash<char>{size_t operator()(const char x)const (return x;)};
_STL_TEMPLATE_NULL struct hash<short>{size_t operator()(const short x)const (return x;)};
_STL_TEMPLATE_NULL struct hash<unsigned short>{size_t operator()(const unsigned short x)const (return x;)};
_STL_TEMPLATE_NULL struct hash<int>{size_t operator()(const int x)const (return x;)};
_STL_TEMPLATE_NULL struct hash<unsigned int>{size_t operator()(const unsigned int x)const (return x;)};
_STL_TEMPLATE_NULL struct hash<long>{size_t operator()(const long x)const (return x;)};
_STL_TEMPLATE_NULL struct hash<unsigned long>{size_t operator()(const unsigned long x)const (return x;)};
_STL_TEMPLATE_NULL struct hash<char*>{size_t operator()(const char* s)const (return _stl_hash_string(s);)};
_STL_TEMPLATE_NULL struct hash<const char*>{size_t operator()(const char* s)const (return _stl_hash_string(s);)};
inline size_t _stl_hash_string(const char* s){
unsigned long h=0;
for(;*s;++s){
h=5*h+*s;
}
return size_t(h);
}
//注意stl中没有提供string类型的hashfunc模板特化版本,需要自己提供
Unordered容器使用
C++11引入的容器unordered_set、unordered_multiset、unordered_map和unordered_multimap更名自GCC2.9的下 容器hash_set、hash_multiset、hash_map和hash_multimap,其底层封装了hashtable.用法与set、multiset、map和multimap类似。
void UnorderedSetCompare() {
unordered_multiset<string>s;
char buf[10];
for (long i = 0; i < INPUTSIZE; i++) {
try
{
snprintf(buf, 10, "%d", rand());
s.insert(string(buf));
}
catch (const std::exception& p)
{
cout << "i= " << i << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds: " << clock() << endl;
cout << "s.size(): " << s.size() << endl;
cout << "s.Max_Size(): " << s.max_size() << endl;
cout << "s.bucket_count():" << s.bucket_count() << endl;
cout << "unordered_multiset.load_factor()= " << s.load_factor() << endl;
cout << "unordered_multiset.max_load_factor()= " << s.max_load_factor() << endl;
cout << "unordered_multiset.max_bucket_count()= " << s.max_bucket_count() << endl;
for (unsigned i = 0; i < 20; i++) {
cout << "bucket #" << i << " has " << s.bucket_size(i) << " elemt " << endl;
}
string target = get_a_string_target();
Clock_Time start_time = clock();
auto ite = ::find(s.begin(), s.end(), target);
cout << "::find(),milli-seconds: " << (clock() - start_time) << endl;
if (ite != s.end()) {
cout << "Find Value!" << endl;
}
else {
cout << "Not Find Value" << endl;
}
start_time = clock();
ite = s.find(target); //比全局::sort函数快很多
cout << "s.find(),milli-seconds: " << (clock() - start_time) << endl;
if (ite != s.end()) {
cout << "Find Value!" << endl;
}
else {
cout << "Not Find Value" << endl;
}
}