当前位置: 首页 > news >正文

让风恒定:在 unordered 的荒原上种下一棵常数级的树

目录

一、HashNode的修改

二、哈希表的修改

三、HTiterator

四、unorder_set的框架

五、unorder_map的框架

六、const_iterator

6.1修改HashTable

6.2修改unorder_set

6.3修改unorder_map

七、完善map

八、源代码

HashTable.h

unorder_set.h

unorder_map.h

test


一、HashNode的修改

template<class T>
struct HashNode
{T _data;//不再是之前的pair<k,v> _kv 了,T有可能是k或者是pairHashNode<T>* _next;HashNode(const T& data):_data(data), _next(nullptr){}
};
  • _data 不再是之前的pair<k,v> _kv 了,,而是依据传过来的T的类型 ,T有可能是k或者是pair
  • HashNote要能接收  来自set的k  key和来自map的pair<k,v>
  • T是哈希表的节点中实际存储的类型

二、哈希表的修改

template<class k,class T,class KeyOfT, class HashFunc = DefaultHashFunc<T>>
class HashTable
{
public: 
...
private:vector<Node*> _table; // 指针数组 , 此时 _table是存储的是内置类型,vector不会清理除桶头节点以外的的空间 ,而上面的存的是自定义类型,会调用析构函数size_t _n=0; // 有效个数
};
  • 增添了一个仿函数参数 class KeyOfT
  • class KeyOfT : 取出哈希表节点中的key (从set中取key,从map的pair<k,v>中取key)
  • HashFunc : 节点中的key(关键码)有可能不是整型,有可能是string等等,你要把它转换成整型 ,这样才能被% ,从而得到哈希值 ,(哈希值决定了该元素在哈希表中的存储位置)

三、HTiterator

template<class k, class T,class Ptr,class Ref, class KeyOfT, class HashFunc = DefaultHashFunc<T>>
struct HTiterator// 在使用HTiterator时,把HTiterator看作 data 的指针
{typedef HashNode<T> Node;typedef HTiterator<k, T, Ptr, Ref, KeyOfT, HashFunc> Self;//两个成员函数Node* _node;HashTable<k, T, KeyOfT,HashFunc>* _ptr;//_table是private ,"_ptr->_table.size()", 谁想用谁,谁就是谁的朋友// HTiterator 想用HashiTable的_table, HTiterator就是HashiTable的朋友HTiterator(Node* node, HashTable<k, T, KeyOfT,HashFunc>* ptr):_node(node), _ptr(ptr)                                       {}                                                                KeyOfT kt;// 取出k 或者 pair<k,v> 中的 k ,反正就是取 kHashFunc hf;//为了让对象可以被%Ref operator*()//iterator* 直接返回iterator中的_node->_data的值{return _node->_data;}Ptr operator->()//iterator-> 直接返回iterator中的_node->_data的地址{return &(_node->_data);}bool operator!=(const Self& s){return _node != s._node;}Self& operator++(){if (_node->_next){_node = _node->_next;}else{size_t hashi =hf( kt(_node->_data)) % (_ptr->_table.size());hashi++;while (hashi < _ptr->_table.size()){if (_ptr->_table[hashi]){_node = _ptr->_table[hashi];return *this;}hashi++;}_node = nullptr;}return *this;}
};
  • 增加模板参数Ptr ,  Ref : 这样既可以传const 类型的值给这个类,也可以传普通类型的值,编译器可以实例化出不同的类 , 免得写两个类
  • 这里相较于红黑树 ,增加了 HashTable<k, T, KeyOfT,HashFunc>* _ptr; 为什么要用哈希表的指针?因为这样我们就可以使用哈希表中的_table ,在++时,我们可能面临着找到下一个桶的难点,可能这个桶的++的位置是空,所以我们要找到下一个不为空的桶的头节点,但是我们不知道ta的地址在哪里?所以需要把哈希表的指针 ,直接传过来,这样就可以用里面的_table,_table是指针数组,ta有每个桶的头节点指针,同时我们还需要,直到_table的size()
  • 在++中,如果下一个节点不为空,就直接走到下一个节点 ,返回this
  • 如果下一个节点为空的话,我们就要先找到这个节点所在的桶的位置,然后再从这个桶的位置找起,前提是不能超过指针数组_table.size()的大小,直到找到不为空的桶的头节点,那么,这个位置就是++的值,如果走完了size() , 还是没找到,那就说明最后一个节点就是空 ,_node=空即可

四、unorder_set的框架

#pragma once#include "HashTable.h"namespace bit
{template<class K>class unordered_set{public:struct SetKeyOfT{const K& operator()(const K& key){return key;}};typedef typename hash_bucket::HashTable<K, K, SetKeyOfT>::iterator iterator;iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}bool Insert(const K& key){return _ht.Insert(key);}hash_bucket::HashNode<const K>* Find(const K& key){return _ht.Find(key);}bool Erase(const K& key){return _ht.Erase(key);}private:hash_bucket::HashTable<K, K, SetKeyOfT> _ht;};
}
  • setkeyofT  : 取出set中哈希表节点中存的key值
  •  typename :  typename  在这里的作用是:告诉编译器  hash_bucket::HashTable<K, K, SetKeyOfT>::iterator  是一个类型,而不是变量或成员
  • Find返回哈希表中的节点,由于这里之前有开散列的open_address命名空间,所以要声明是hash_bucket命名空间的节点
  • 返回值用const限制防止外界修改
  • 这里_ht少传了个参数Hashfunc,其实是不用传的,因为Hashfunc有缺省值,可以不用传

五、unorder_map的框架

#pragma once#include "HashTable.h"namespace bit
{template<class K, class V>class unordered_map{public:struct MapKeyOfT{const K& operator()(const pair<K, V>& kv){return kv.first;}};typedef typename hash_bucket::HashTable<K, pair<K, V>, MapKeyOfT>::iterator iterator;iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}bool Insert(const pair<K, V>& kv){return _ht.Insert(kv);}hash_bucket::HashNode<const pair<K, V>>* Find(const K& key){return _ht.Find(key);}bool Erase(const K& key){return _ht.Erase(key);}private:hash_bucket::HashTable<K, pair<K, V>, MapKeyOfT> _ht;};}
  • MapKeyOfT : 取出map中哈希表节点pair<k,v>  _data中存的first值
  •  typename :  typename  在这里的作用是:告诉编译器  hash_bucket::HashTable<K, K, SetKeyOfT>::iterator  是一个类型,而不是变量或成员
  • Find返回哈希表中的节点,由于这里之前有开散列的open_address命名空间,所以要声明是hash_bucket命名空间的节点
  • 返回值用const限制防止外界修改
  • 这里_ht少传了个参数Hashfunc,其实是不用传的,因为Hashfunc有缺省值,可以不用传

回顾一下pair的定义: 

template <class T1, class T2>
struct pair
{
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
pair(): first(T1()), second(T2())
{}
pair(const T1& a, const T2& b): first(a), second(b)
{}};

六、const_iterator

6.1修改HashTable
	template<class k,class T,class KeyOfT, class HashFunc = DefaultHashFunc<T>>class HashTable{typedef HashNode<T> Node;public:typedef HTiterator<k, T, T*,T&,KeyOfT, HashFunc> iterator;typedef HTiterator<k, T, const T*,const T&, KeyOfT, HashFunc> const_iterator;iterator begin(){for (size_t i = 0; i < _table.size(); i++){Node* cur = _table[i];if (cur){return iterator(cur, this);}}return iterator(nullptr, this);}iterator end(){return iterator(nullptr, this);}const_iterator begin()const//{for (size_t i = 0; i < _table.size(); i++){Node* cur = _table[i];if (cur){return const_iterator(cur, this);}}return const_iterator(nullptr, this);}HashTable(){_table.resize(10, nullptr);// 一开始都是空}~HashTable()pair<iterator, bool> Insert(const T& data)// 前插和后插都一样void Print()iterator Find(const k& key) // 返回这个位置的节点指针	bool Erase(const k& key)	private:vector<Node*> _table; // 指针数组 , 此时 _table是存储的是内置类型,vector不会清理除桶头节点以外的的空间 ,而上面的存的是自定义类型,会调用析构函数size_t _n=0; // 有效个数};}
  • 增加const的begin(),和const的end(),在函数名后面加const是限定这个对象不能在这个函数中被修改,在返回值的前面加const是表示这个返回值不允许被修改
  • 但此时会发现一个问题,在被const修饰后的函数后,这个对象不能修改,也就是说,这个this是const类型的,而用这个值去初始化const_iterator ,const_iterator 类中的构造函数如下 :
HTiterator(Node* node, HashTable<k, T, KeyOfT,HashFunc>* ptr):_node(node), _ptr(ptr)                                        
{}                                    
  • 其中这个ptr是普通类型的,这就导致const类型传给普通类型权限会遭到放大,所以这里就会出错
  • 解决方法 :  HashTable<k, T, KeyOfT,HashFunc>* ptr要加const修饰,让_ptr是const 不就行了,那难道这里要写两个类型的形参的函数,构成重载吗?
	HTiterator(Node* node, const HashTable<k, T, KeyOfT,HashFunc>* ptr):_node(node), _ptr(ptr)                                        {}  HTiterator(Node* node, HashTable<k, T, KeyOfT,HashFunc>* ptr):_node(node), _ptr(ptr)                                        {}                             
  • 其实不用直接把哈希表指针设置为const类型 ,  在HTiterator中反正又不修改哈希表,只是查询了一下_table的size()以及存储的桶的头节点 
  • 如果是普通的this给ptr ,也没问题,权限是可以缩小的
6.2修改unorder_set
typedef typename hash_bucket::HashTable < k, k, setkeyofT,DefaultHashFunc<k>>::const_iterator iterator;
typedef typename hash_bucket::HashTable < k, k, setkeyofT, DefaultHashFunc<k>>::const_iterator const_iterator;iterator begin()const
{return _ht.begin();
}iterator end()const
{return _ht.end();
}
  • unorder_set是不允许被修改的,所以它的普通迭代器以及const迭代器都是由HTiterator中的const迭代器来的
6.3修改unorder_map
typedef typename hash_bucket::HashTable < k, pair<k,v>, mapkeyofT, DefaultHashFunc<k>>::iterator iterator;typedef typename hash_bucket::HashTable < k, pair<k, v>, mapkeyofT, DefaultHashFunc<k>>::const_iterator const_iterator;iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}const_iterator begin() const{return _ht.begin();}const_iterator end() const{return _ht.end();}
  • Map中是k是不允许修改的,v是允许修改的
  • 同时 ,增加const迭代器,使kv都不能修改

七、完善map

#pragma once
#include"HashTable.h"
namespace bit
{template<class k,class v>class unordered_map{public:struct mapkeyofT{const k& operator()(const pair<k,v>& key){return key.first;}};typedef typename hash_bucket::HashTable < k, pair<const k,v>, mapkeyofT, DefaultHashFunc<k>>::iterator iterator;typedef typename hash_bucket::HashTable < k, pair<const k, v>, mapkeyofT, DefaultHashFunc<k>>::const_iterator const_iterator;iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}const_iterator begin() const{return _ht.begin();}const_iterator end() const{return _ht.end();}pair<iterator,bool> insert(const pair<const k,v>& _kv){return _ht.Insert(_kv);}v& operator[](const k& key){pair<iterator, bool> ret = insert(make_pair(key, v()));return ret.first->second;//ret.first->_node->second,把iterator当 data* 即可}private:hash_bucket::HashTable<k,pair<const k,v>, mapkeyofT,DefaultHashFunc<k>> _ht;};}
  • 为了防止map中的k类型的first被修改, 给所有的k类型都加上了const 修饰  ,同时重载了operator[] , 可以使他的v类型的值通过k类型的值查找到然后修改
  • 从而修改map中的insert的返回值为pair<iterator,bool>  ,同样也要修改哈希表中的insert ,从而要修改set中的insert

unorder_set: 

pair<iterator,bool> insert(const k& key)
{//先用HashTable中的iterator接受一下普通迭代器,因为_ht.Insert是普通,之所以用HashTable中的iterator//因为set中的iterator是const的来的,然后再用普通迭代器构造const迭代器pair<typename hash_bucket::HashTable<k, k, setkeyofT>::iterator, bool> ret = _ht.Insert(key);return pair<const_iterator, bool>(ret.first, ret.second);
}
  • 在unordered_set中 , 由于其普通迭代器和const迭代器都是const迭代器,所以在unordered_set中的Insert的返回值返回的pair<iterator, bool>实际上的迭代器是const迭代器
    _ht调用的HashiTable 的 Insert的返回值的是pair<iterator, bool>,其中的迭代器是普通迭代器,那么这里就会出现类型不匹配 ,
  • 先用HashTable中的iterator接受一下普通迭代器,因为_ht.Insert是普通,之所以用HashTable中的iterator  ,是因为unorder_set中的iterator是const的来的,然后再用普通迭代器构造const迭代器
  • 那么我们要对HTIterator 类进行修改,添加一个普通迭代器类型,这样能够接收普通iterator 编写一个构造函数,即可以让普通迭代器转化构造出const迭代器
template<class k, class T,class Ptr,class Ref, class KeyOfT, class HashFunc = DefaultHashFunc<T>>
struct HTiterator// 在使用HTiterator时,把HTiterator看作 data 的指针
{typedef HashNode<T> Node;typedef HTiterator<k, T, Ptr, Ref, KeyOfT, HashFunc> Self;typedef HTiterator<k, T, T*, T&, KeyOfT, HashFunc> iterator;//两个成员函数Node* _node;const HashTable<k, T, KeyOfT,HashFunc>* _ptr;//_table是private ,"_ptr->_table.size()", 谁想用谁,谁就是谁的朋友// HTiterator 想用HashiTable的_table, HTiterator就是HashiTable的朋友HTiterator(Node* node, const HashTable<k, T, KeyOfT,HashFunc>* ptr)//这里会发生const去实例化普通,const实参传给普通形参 权限会放大:_node(node), _ptr(ptr)                                        //所以要加const修饰,那用const去初始化普通,这也不对啊,那我们{}                                                                 //让_ptr是const 不就行了,在HTiterator中反正又不修改_ptr //如果是普通的this给ptr ,也没问题,权限可以缩小HTiterator(const iterator& it)//普通迭代器构造const迭代器(HTiterator是const时):_node(it._node), _ptr(it._ptr){}
....
};
  • 那么当迭代器模板类实例化为const迭代器的时候,我们的构造该构造函数就是构造函数,当迭代器模板类实例化为普通迭代器的时候,我们该构造函数就是拷贝构造函数

哈希表中的insert

//如果Insert如果不扩容 ,不断插入,效率得不到保障
//所以开散列必须扩容 ,不过负载因子可以放大一点
pair<iterator, bool> Insert(const T& data)// 前插和后插都一样
{HashFunc hf;//转换成能被%KeyOfT kt;//取data的kiterator it = Find(kt(data));if (it!=end()){return make_pair(it, false);}if (_n==_table.size()){size_t newsize = _table.size() * 2;//这里不能直接调用插入 ,因为旧的Hashable还要delete之前开好的空间//只需要把旧的Hashable的每个桶的头节点给牵过来即可vector<Node*>newtable;newtable.resize(newsize, nullptr);//遍历旧表 ,把每个桶的头节点给牵过来 ,挂到新表for (size_t i = 0; i < _table.size(); i++){Node* cur = _table[i];while (cur){Node* next = cur->_next;//保存一下cur的下个节点size_t hashi = hf(kt(cur->_data)) % newsize;//找到cur该在newtable中存储的位置cur->_next=newtable[hashi];//把 cur 节点给牵过来 ,挂到新表newtable[hashi] = cur;cur = next; }_table[i] = nullptr;}_table.swap(newtable);//底层是start , finish ,end 交换}size_t hashi = hf(kt(data)) % _table.size();// 头插Node* newnode = new Node(data);newnode->_next = _table[hashi];// ps : 把_table[hashi]看作一个代理身份_table[hashi] = newnode;_n++;return make_pair(iterator(newnode,this), true);
}

由于insert中调用的fond函数,所以fond的返回值要修改,在erase函数里面又调用了fond的函数,所以,erase也要稍微修改,不过这些修改都直接放在源代码里面了

八、源代码

HashTable.h
namespace hash_bucket
{template<class T>struct HashNode{T _data;//不再是之前的pair<k,v> _kv 了,T有可能是k或者是pairHashNode<T>* _next;HashNode(const T& data):_data(data), _next(nullptr){}};//HTiterator中(HTiterator(Node* node, HashTable<k, T, KeyOfT>* ptr))用到了HashTable ,//在HashTable又 typedef HTiterator<k, T, KeyOfT, HashFunc> iterator;//那谁在前谁在后呢////前置声明template<class k,class T,class KeytOfT,class HashFunc>class HashTable;//告诉编译器HashTable<k, T, KeyOfT>是定义了的,不用急着去确认ta ,因为编译器默认向前找 template<class k, class T,class Ptr,class Ref, class KeyOfT, class HashFunc = DefaultHashFunc<T>>struct HTiterator// 在使用HTiterator时,把HTiterator看作 data 的指针{typedef HashNode<T> Node;typedef HTiterator<k, T, Ptr, Ref, KeyOfT, HashFunc> Self;typedef HTiterator<k, T, T*, T&, KeyOfT, HashFunc> iterator;//两个成员函数Node* _node;const HashTable<k, T, KeyOfT,HashFunc>* _ptr;//_table是private ,"_ptr->_table.size()", 谁想用谁,谁就是谁的朋友// HTiterator 想用HashiTable的_table, HTiterator就是HashiTable的朋友HTiterator(Node* node, const HashTable<k, T, KeyOfT,HashFunc>* ptr)//这里会发生const去实例化普通,const实参传给普通形参 权限会放大:_node(node), _ptr(ptr)                                        //所以要加const修饰,那用const去初始化普通,这也不对啊,那我们{}                                                                 //让_ptr是const 不就行了,在HTiterator中反正又不修改_ptr //如果是普通的this给ptr ,也没问题,权限可以缩小HTiterator(const iterator& it)//普通迭代器构造const迭代器(HTiterator是const时):_node(it._node), _ptr(it._ptr){}KeyOfT kt;// 取出k 或者 pair<k,v> 中的 k ,反正就是取 kHashFunc hf;//为了让对象可以被%Ref operator*()//iterator* 直接返回iterator中的_node->_data的值{return _node->_data;}Ptr operator->()//iterator-> 直接返回iterator中的_node->_data的地址{return &(_node->_data);}bool operator!=(const Self& s){return _node != s._node;}Self& operator++(){if (_node->_next){_node = _node->_next;}else{size_t hashi =hf( kt(_node->_data)) % (_ptr->_table.size());hashi++;while (hashi < _ptr->_table.size()){if (_ptr->_table[hashi]){_node = _ptr->_table[hashi];return *this;}hashi++;}_node = nullptr;}return *this;}};template<class k,class T,class KeyOfT, class HashFunc = DefaultHashFunc<T>>class HashTable{typedef HashNode<T> Node;template<class k, class T, class Ptr, class Ref, class KeyOfT, class HashFunc>friend struct HTiterator;public:typedef HTiterator<k, T, T*,T&,KeyOfT, HashFunc> iterator;typedef HTiterator<k, T, const T*,const T&, KeyOfT, HashFunc> const_iterator;iterator begin(){for (size_t i = 0; i < _table.size(); i++){Node* cur = _table[i];if (cur){return iterator(cur, this);}}return iterator(nullptr, this);}iterator end(){return iterator(nullptr, this);}const_iterator begin()const//{for (size_t i = 0; i < _table.size(); i++){Node* cur = _table[i];if (cur){return const_iterator(cur, this);}}return const_iterator(nullptr, this);}const_iterator end()const //const是修饰对象本身 : *this,所以this要用const迭代器指针接受 {return const_iterator(nullptr, this);}HashTable(){_table.resize(10, nullptr);// 一开始都是空}~HashTable(){for (size_t i = 0; i < _table.size(); i++){Node* cur=_table[i];while (cur){Node* tmp = cur->_next;delete cur;cur = tmp;}_table[i] = nullptr;}}/*HashTable(const HashTable<k,v> re):_table(re._table),_n(re._n){ }*///如果不扩容 ,不断插入,效率得不到保障//所以开散列必须扩容 ,不过负载因子可以放大一点pair<iterator, bool> Insert(const T& data)// 前插和后插都一样{HashFunc hf;//转换成能被%KeyOfT kt;//取data的kiterator it = Find(kt(data));if (it!=end()){return make_pair(it, false);}if (_n==_table.size()){size_t newsize = _table.size() * 2;//这里不能直接调用插入 ,因为旧的Hashable还要delete之前开好的空间//只需要把旧的Hashable的每个桶的头节点给牵过来即可vector<Node*>newtable;newtable.resize(newsize, nullptr);//遍历旧表 ,把每个桶的头节点给牵过来 ,挂到新表for (size_t i = 0; i < _table.size(); i++){Node* cur = _table[i];while (cur){Node* next = cur->_next;//保存一下cur的下个节点size_t hashi = hf(kt(cur->_data)) % newsize;//找到cur该在newtable中存储的位置cur->_next=newtable[hashi];//把 cur 节点给牵过来 ,挂到新表newtable[hashi] = cur;cur = next; }_table[i] = nullptr;}_table.swap(newtable);//底层是start , finish ,end 交换}size_t hashi = hf(kt(data)) % _table.size();// 头插Node* newnode = new Node(data);newnode->_next = _table[hashi];// ps : 把_table[hashi]看作一个代理身份_table[hashi] = newnode;_n++;return make_pair(iterator(newnode,this), true);}void Print(){KeyOfT kt;for (size_t i = 0; i < _table.size(); i++){printf("[%d]->", i);Node* cur = _table[i];//桶的头while (cur)//把这个桶走完{cout <<kt(cur->_data) << "->"<<kt(cur->_data)<<"->";cur = cur->_next; }cout << "NULL" << endl;}}iterator Find(const k& key) // 返回这个位置的节点指针{HashFunc hf;KeyOfT kt;size_t hashi = hf(key) % _table.size();Node* cur = _table[hashi];while (cur){if (kt(cur->_data) == key){return iterator(cur,this);}cur = cur->_next;}return iterator(nullptr,this);}bool Erase(const k& key){HashFunc hf;KeyOfT kt;iterator it = Find(kt(key));if (it._node == nullptr){return false;}size_t hashi = hf(key) % _table.size();Node* cur = _table[hashi];Node* tmp = cur;while (cur){if (kt(cur->_data) == key){if (tmp==cur)//删桶的头节点{_table[hashi] = cur->_next;delete cur;_n--;return true;}else{tmp->_next = cur->_next; delete cur;_n--;return true;}}tmp = cur;cur = cur->_next;}}private:vector<Node*> _table; // 指针数组 , 此时 _table是存储的是内置类型,vector不会清理除桶头节点以外的的空间 ,而上面的存的是自定义类型,会调用析构函数size_t _n=0; // 有效个数};}
unorder_set.h
#pragma once
#include"HashTable.h"
namespace bit
{template<class k>class unordered_set{public:struct setkeyofT{const k& operator()(const k&key){return key;}};typedef typename hash_bucket::HashTable < k, k, setkeyofT,DefaultHashFunc<k>>::const_iterator iterator;typedef typename hash_bucket::HashTable < k, k, setkeyofT, DefaultHashFunc<k>>::const_iterator const_iterator;iterator begin()const{return _ht.begin();}iterator end()const{return _ht.end();}//  pair<iterator,bool> insert(const k& key){//先用HashTable中的iterator接受一下普通迭代器,因为_ht.Insert是普通,之所以用HashTable中的iterator//因为set中的iterator是const的来的,然后再用普通迭代器构造const迭代器pair<typename hash_bucket::HashTable<k, k, setkeyofT>::iterator, bool> ret = _ht.Insert(key);return pair<const_iterator, bool>(ret.first, ret.second);}private:hash_bucket::HashTable<k, k, setkeyofT, DefaultHashFunc<k>> _ht;};}
unorder_map.h
#pragma once
#include"HashTable.h"
namespace bit
{template<class k,class v>class unordered_map{public:struct mapkeyofT{const k& operator()(const pair<k,v>& key){return key.first;}};typedef typename hash_bucket::HashTable < k, pair<const k,v>, mapkeyofT, DefaultHashFunc<k>>::iterator iterator;typedef typename hash_bucket::HashTable < k, pair<const k, v>, mapkeyofT, DefaultHashFunc<k>>::const_iterator const_iterator;iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}const_iterator begin() const{return _ht.begin();}const_iterator end() const{return _ht.end();}pair<iterator,bool> insert(const pair<const k,v>& _kv){return _ht.Insert(_kv);}v& operator[](const k& key){pair<iterator, bool> ret = insert(make_pair(key, v()));return ret.first->second;//ret.first->_node->second,把iterator当 data* 即可}private:hash_bucket::HashTable<k,pair<const k,v>, mapkeyofT,DefaultHashFunc<k>> _ht;};}
test
#include<iostream>
//#include<unordered_set>
//#include<unordered_map>
//#include<set>
using namespace std;#include"UnOrderedSet.h"
#include"UnOrderedMap.h"int main()
{bit::unordered_set<int> us;us.insert(3);us.insert(1);us.insert(3);us.insert(4);us.insert(5);us.insert(0);bit::unordered_set<int>::iterator it = us.begin();while (it != us.end()){//*it+=10;cout << *it << " ";++it;}cout << endl;bit::unordered_map<string, string> dict;dict.insert(make_pair("sort", "排序"));dict.insert(make_pair("left", "左边"));dict.insert(make_pair("insert", "插入"));dict.insert(make_pair("sort", "xxx"));/*dict["sort"] = "排序";dict["insert"] = "插入";dict["string"] = "字符串";dict["left"];*/for (auto& kv : dict)//kv是pair<k,v> {cout << kv.first << ":" << kv.second << endl;}return 0;
}

http://www.dtcms.com/a/407090.html

相关文章:

  • 图书网站建设实训总结前端培训心得
  • 【Spring Cloud Alibaba】Seata(一)
  • 仓颉编程语言的stdx包介绍及使用
  • 长沙网站制作方法wordpress获得所有分类
  • 无限空间 网站网站新闻页面无法翻页
  • 民族团结 网站建设wordpress底部版权插件
  • Markdown转PDF工程化实现含图片支持与样式控制
  • Linux下安装Kafka 3.9.1
  • kafka vs rocketmq
  • 1.DHCP服务器
  • 河南网站备案代理苏州专业网站建设公司
  • 电商网站seo公司网页怎么做成网站
  • 与TCP相比,UDP有什么优缺点?
  • 从0到1制作一个go语言服务器 (一) 配置
  • 沙姆定律原理/公式推导
  • leetcode 98 验证二叉搜索树
  • 国外外包网站天津百度搜索排名优化
  • 中国建设银行网站企业网银收费怎么在外国网站上找产品做跨境电商
  • 合肥网站优化搜索怎么做网站优化 site
  • 建站网络公司建筑二级建造师培训机构
  • 网站安全架构网站建设注意哪些问题
  • Python个性化新闻系统 新闻情感分析推荐系统 爬虫+情感分析+推荐算法(附源码)✅
  • Qt容器QList、QLinkedList、QVector特性浅谈
  • 时间序列分析新视角论文分享:LLM 搬进时间序列
  • 黑盒渗透DC-2报告总结
  • 英语培训网站建设东莞网站建设乐云seo
  • 怎么清理网站后门文件.net做网站教程
  • Qt常用控件之QLCDNumber
  • Java 实现LCRIME 雾凇变体算法
  • 做logo网站的公司高质量的猎建筑人才