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

化工网站建设价格微信客户端小程序

化工网站建设价格,微信客户端小程序,邹平网站建设公司报价,档案馆网站建设文章目录 使用哈希表封装myunordered_set和myunordered_map实现出复用哈希表框架,并支持insert支持迭代器的实现constKey不能被修改unordered_map支持[ ]结语 我们今天又见面啦,给生活加点impetus!!开启今天的编程之路&#xff01…

文章目录

  • 使用哈希表封装myunordered_set和myunordered_map
    • 实现出复用哈希表框架,并支持insert
    • 支持迭代器的实现
    • const
    • Key不能被修改
    • unordered_map支持[ ]
    • 结语

我们今天又见面啦,给生活加点impetus!!开启今天的编程之路!!
在这里插入图片描述
今天我们使用前面已经实现过的哈希表来实现myunordered_set和unordered_map
作者:٩( ‘ω’ )و260
我的专栏:C++进阶,C++初阶,数据结构初阶,题海探骊,c语言
欢迎点赞,关注!!

使用哈希表封装myunordered_set和myunordered_map

实现出复用哈希表框架,并支持insert

与map和set相比而言,unordered系列的实现更加复杂。
首先,unoedered_set是key类型,unordered_map是key,value类型,要实现一个底层实现两种数据结构,我们必须使用模版,这里我们传递三个参数,第一个是K,第二个是T,第三个是KeyOfT
三个模版的作用

第一个:传递K是为了find和erase接口,因为find和erase接口只能够使用key作为实参
第二个:代表哈希表中结点的存储类型
第三个:因为我们来寻找映射位置的时候需要取模,key一般可以直接取,但是pair必须需要取出其中的key

接下来我们来看代码:

template<class K>
class myunordered_set
{struct SetOfT{const K& operator(const K&key){return key;}}
public:private:HashTable<K,K,SetOfT> _tables;//底层结构是哈希桶
}
template<class K,class V>
class myunordered_map
{struct MapOfT{K& operator()(const pair<K,V>&kv){return kv.first;}}
private:HashTable<K,pair<K,V>,MapOfT> _tables;底层结构是哈希桶
}

因为存储的数值不确定,所以哈希结点也需要修改:

template<class T>
struct HashNode
{T _data;HashNode<K>*_next;HashNode(const T&data):_data(data),_next(nullptr){}
}

接下来我们来写insert函数,insert是重点,我们主要还写写的是伪代码。
Insert操作还是主题思路不变。
1:先求key映射的偏移位置(细节:key可能需要取,其次,可能需要转换成整形)这里会用到两层仿函数
2:不断头插
3:检查是否需要扩容(细节:定义的是哈希数组,而非一个哈希表,直接把结点给他拿下来就行)
4:注意返回值:我们直接模仿库中的insert函数返回pair<iterator,bool>类型(为什么我们实现这个insert函数重载?因为为了实现unordered_map支持operator[ ]做准备)
在这里插入图片描述
来看代码实现
注意:此时迭代器里面有两个成员变量,一个是_node,一个是哈希表,原因会在下面说.

pair<iterator,bool> Insert()(const T&data)
{KeyOfT kot;//取keyHash hs;//转整形,只有在取模的时候才用iterator it=Find(kot(data));if(it!=End()) return {it,false};//插入失败+去重if (_n == _tables.size()){//两种逻辑,优先第二种,第一种是拷贝结点,删除旧结点,第二种是直接把结点给拿下来//第一种:创建新的哈希表,第二种:创建新的数组//HashTable<K, V, Hash> newht(__stl_next_prime(_tables.size() + 1));//加1才能够继续取到更到的素数遍历旧表,将旧表的数据全部重新映射到新表//for (int i = 0;i < _tables.size();i++)//{//	Node* cur = _tables[i];//	while (cur)//	{//		newht.Insert(cur->_kv);//		cur = cur->_next;//	}//}//_tables.swap(newht._tables);//为什么第一种方法会重新再拷贝构造,因为复用的时候会调用new这个关键字vector<Node*> newtables(__stl_next_prime(_tables.size() + 1),nullptr);//数组初始化为n个nullptrfor (size_t i = 0;i < _tables.size();i++){Node* cur = _tables[i];while (cur){Node* next = cur->_next;//这里我们存储一下cur的下一个位置,因为当我们将cur下一个位置放下来的时候,_next被修改,所以需要提前记录一下//重新计算映射位置size_t hashi = hs(kot(cur->_data)) % newtables.size();cur->_next = newtables[hashi];newtables[hashi] = cur;cur = next;}//因为原来的旧链表的值已经被使用过了,所以我只直接将其置为nullptr_tables[i] = nullptr;}//底层是数组,例如vector或者string,调用库中的交换函数_tables.swap(newtables);}size_t hashi = hs(kot(data)) % _tables.size();Node* newnode = new Node(data);//这里不是new Node(kot(data));//pair类型结点里面存的是pair,不是key//优先选择头插进入链表,尾插需要向后遍历,头插分两种情况,映射位置为空或有数据,下面的代码两者都可以适用newnode->_next = _tables[hashi];_tables[hashi] = newnode;_n++;return {Iterator(newnode,this),true};
}

支持迭代器的实现

首先,因为哈希表中成员是一个单链表,所以我的的迭代器肯定是单向迭代器,即我们的迭代器只能支持++,不支持- -,同样也不支持随机访问。

迭代器的成员变量肯定是有一个_node。
当我们需要返回下一个位置的迭代器的时候,如果下一个位置不为空,那么迭代器中的指针直接向后走一步就可以了,如果下一个位置为空,就需要遍历到下一个不为空的位置的桶,返回桶的第一个位置即可。
此时我的cur都在遍历这个单链表了,我们根本找不到哈希表中下一个不为空的位置,那我们应该怎样找到下一个不为空的桶呢?我们必须传递一个哈希表过去!!
来看代码实现:
细节:这里我直接加上普通迭代器和const迭代器一起实现了,不然等下解释的太绕了
实现const迭代器的话,就会多2个模版参数,主要是返回值operator*和operator->。
而且,在迭代器内部有this指针,我们只用操作_node的指向即可

template<class K,class T,class Ref,class Ptr,class KeyOfT,class Hash>
struct HTIterator
{typedef HashNode<T> Node;typedef HashTable<K,T,KeyOfT,Hash> HT;typedef HTIterator<K,T,Ref,Ptr,keyofT,Hash>  Self;Node*_node;//成员变量HT*_pht;//成员变量Self& operator++(){if(_node->_next)//指向的下一个不为空{_node=_node->_next;}else{//下一个结点为空,需要向后找到不为空的桶KeyOfT kot;Hash hs;size_t hashi=hs(kot(_node->_data))%_pht->_tables.size();hashi++;//需要跳过当前桶while(hashi<_pht->_tables.size()){if(_pht->_tables[hashi]){_node=_pht->_tables[hashi];break;}++hashi;}if(hashi == _pht->_tables.size())//哈希表遍历遍历完了都还没有找到{_node=nullptr;}}return *this;}
}

接下来我再来实现迭代器中不重要的操作:
直接看代码即可:

Ref operator*()
{return _node->_data;
}
Ptr operator->()
{return &_node->_data;//箭头会返回对应结点的指针,编译器为了优化,自己会再添加一个箭头,这个箭头就是*.操作的结合
}
bool operator==(const Self& s)
{return _node == s._node;
}
bool operator!=(const Self& s)
{return _node != s._node;
}

const

const迭代器中迭代器部分我们已经完成了,接下来我们来看HashTable的部分。
这里需要解释Begin(),begin肯定是返回桶中链表的第一个结点即可

因为比较简单,直接来看代码即可:

Iterator Begin()//返回第一个桶的第一个结点
{if (_n == 0)return End();//此时没有结点,Begin()就是End()for (size_t i = 0;i < _tables.size();i++){if (_tables[i])return Iterator(_tables[i] ,this);}return End();//语法逻辑上来说必须要加,不能用运行逻辑来概括语法逻辑,万一里面的程序出错,可能就没有返回值了
}Iterator End()
{return Iterator(nullptr, this);
}//错误积累:如果报错不能将initializer list转换成啥,大概率编译器是将{}识别成这个作用了,但是我的目的是多参数来进行隐式类型转换
Const_Iterator Begin() const//返回第一个桶的第一个结点
{if (_n == 0)return End();for (size_t i = 0;i < _tables.size();i++){if (_tables[i]) return Const_Iterator(_tables[i], this);}return End();
}Const_Iterator End()const
{return Const_Iterator(nullptr, this);
}

Key不能被修改

这个也比较简单,只要将第二个模版参数对应的K修改为const K即可,随后对应的typedef部分也需要修改一下。

unordered_map支持[ ]

因为前面已经实现过,直接来看代码:

V& operator[](const K& key)
{pair<iterator, bool> ret = Insert({key,V()});//直接复用上面的Insert,本质上还是调用的底层return ret.first->second;
}

结语

感谢大家阅读我的博客,不足之处欢迎指正,感谢大家的支持
逆水行舟,楫摧而志愈坚;破茧成蝶,翼湿而心更炽!!加油!
在这里插入图片描述

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

相关文章:

  • 设计网站大全扣西湖南岚鸿首选做博客和做网站
  • 网站官网域名服务费岳池住房和城乡建设厅网站
  • 做网站的合同wordpress返回插件
  • 温州网站制作系统响应式网站背景
  • 天水 网站建设招聘泉州做网站优化价格
  • 门户网站 开发语言WordPress众筹网站主题
  • hexo做网站seo神马网站推广器
  • 网站开发课程有哪些网站更换内容
  • 做网站用小型机或服务器给人做网站
  • 网站建设过程小结共享网站的建设与规划
  • 网站买空间网站开发与系统开发
  • 福州网站建设团队c 网站开发模式
  • 泌阳县网站建设江苏工程信息网
  • 江苏常州网站建设福州有名的公司网站设计
  • 货运代理公司wordpress建站seo好做吗
  • 做房产网站有哪些网站首页图
  • .net 接单网站深圳专业做网站技术
  • 钓鱼网站免费空间网站开发维护运维
  • 威海 网站开发asp美食网站源码
  • 苏州做网站哪家专业企业推广哪个平台好
  • 明珠信息港网站建设专家旅游网站策划案
  • 蓬莱有做网站的吗修改wordpress登录背景图
  • 邢台做企业网站万能证件p图
  • 网站信息备案管理系统企业信息网查询系统
  • 企业网站管理系统用户裁剪图网站
  • 一个网站建设需要多少人力江苏九天建设有限公司网站
  • 优秀的网站设计图片手机app免费制作
  • 网页视频制作杭州百度人工优化
  • 网站建设公司税负率平面设计多久能学会
  • 宝安网站制作培训wordpress设置404