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

菏泽哪里有做网站的新东方考研班收费价格表

菏泽哪里有做网站的,新东方考研班收费价格表,wap端网站建设,网页翻译工具文章目录 使用哈希表封装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/wzjs/229703.html

相关文章:

  • 网站图片展示方式浙江网站推广运营
  • 网站后台ftp账户seo工资一般多少
  • 免费建设手机网站google搜索引擎官网
  • 做旅游网站的产品经理如何家居seo整站优化方案
  • 怎么做网站备案2022年最好用的搜索引擎
  • 做网站维护工商经营范围是什么sem推广是什么
  • 长宁区网站建设设全网营销培训
  • 做的漂亮的商务网站泉州关键词搜索排名
  • 潍坊 区网站建设seo推广优化官网
  • 自己怎么做独立外贸网站快手作品免费推广软件
  • wordpress 无限嵌套百度爱采购优化软件
  • 网站建设需要注意的江西seo推广方案
  • 免费申请做网站平台百度云资源链接分享群组
  • 前端真的烂大街了吗惠州seo代理商
  • wordpress评论独立谷歌搜索引擎seo
  • 西安网站seo排名优化我为什么不建议年轻人做运营
  • jsp做网站怎么打开360关键词指数查询
  • 深圳深圳网站建设公司seo工作职位
  • 北京发布会直播太原百度seo排名软件
  • 做公司网站成本一个企业seo网站的优化流程
  • 北京网站开发怎么做网页链接
  • 网站服务器租用一年多少钱啊东莞seo优化排名
  • 上海网站公司建设百度seo指数查询
  • 个人网站域名seo优化招聘
  • 朝阳区外贸公司有哪些seo综合查询国产
  • 家具flash网站模板下载搜狗网站收录提交入口
  • 网络营销文案标题连云港seo公司
  • 中卫平面设计招聘杭州网站优化方案
  • 网站定制开发是什么意思专业seo培训
  • 网站开发是前端还是后端上海关键词优化方法