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

网站建设软著以图搜图百度识图网页版

网站建设软著,以图搜图百度识图网页版,运城市做网站公司,ecshop二次开发网站开发心得本篇建立在已经熟悉map/set模拟实现和开散列的模拟实现的基础上,关于开散列,可以看上一篇文章: 【数据结构】哈希——闭散列/开散列模拟实现(C)-CSDN博客本文对比分析了C中unordered_map/unordered_set与map/set的主要区别。底层实现上&#…

本篇建立在已经熟悉map/set模拟实现和开散列的模拟实现的基础上,关于开散列,可以看上一篇文章:

【数据结构】哈希——闭散列/开散列模拟实现(C++)-CSDN博客本文对比分析了C++中unordered_map/unordered_set与map/set的主要区别。底层实现上,前者采用哈希表(O(1)时间复杂度),后者使用红黑树(O(logN))。重点探讨了哈希冲突的两种解决方案:闭散列(开放定址法)和开散列(哈希桶)。闭散列通过线性探测或二次探测解决冲突,但存在效率问题;开散列则通过链表存储冲突元素,效率更高。文章还提供了哈希表的模拟实现代码,包括插入、查找、删除等操作,并比较了两种容器在百万级数据下的性能差异。 https://blog.csdn.net/suimingtao/article/details/149002209
【数据结构】C++的map/set模拟实现(红黑树作底层)-CSDN博客文章浏览阅读777次,点赞11次,收藏26次。本文介绍了基于红黑树实现C++中的map和set容器。通过复用单一红黑树结构,分别处理K模型(set)和KV模型(map)。重点内容包括:1) 红黑树改造,引入KeyOfValue仿函数解决不同类型值比较问题;2) 迭代器实现,包括++/--操作的中序遍历逻辑;3) map的[]运算符重载,通过insert返回pair 实现。相比传统双树实现方式,这种高级复用方案减少了代码冗余,同时保持了高效性能,插入操作时间复杂度为O(logN)。  https://blog.csdn.net/suimingtao/article/details/148928079

迭代器实现

在实现unordered_map/unordered_set之前,先将开散列的迭代器实现一下

迭代器的结构

对于迭代器来说,也需要传KOfT,Hash参数,还需要一个该哈希表的指针(即下面的_pht),关于原因稍候早说

template<class K,class T,class KOfT,class Hash,class Ref,class Ptr>
struct HashIterator
{typedef HashNode<T> Node;typedef HashTable<K, T, KOfT, Hash> HT;typedef __HashIterator<K, T, KOfT, Hash,Ref,Ptr> Self;//迭代器本身HashIterator(Node* node,HT* pht)//默认构造:_node(node),_pht(pht){ }
private:Node* _node;//每个桶中的节点HT* _pht;//当一个桶走完时,为了可以找到下一个桶,需要该哈希表的指针};

迭代器的解引用 

迭代器中主要存的还是一个节点的指针,即_node,对于operator*和operator->重载,了解过map/set的都知道,operator*重载对应set的解引用,因为set中只存key,解引用时也只需要"*";operator->重载对应map的解引用,因为map中存key和value,解引用时肯定需要"->"指定对应的值

Ref operator*()//unordered_set的解引用
{return _node->_data;
}Ptr operator->()//unordered_map的解引用
{return &_node->_data//在调用"it->first"时,其实是调用了"it->->first",这里编译器省略了第一次"->",而这里返回的就是第一次调用的结果,即pair类型的地址
}

 顺便将等于和不等于重载实现一下

bool operator!=(Self it)
{return _node != it._node;
}bool operator==(Self it)
{return _node == it._node;
}

 迭代器的++

unordered_map/unordered_set的迭代器是单向迭代器,因此只有++,没有--

假设现在的迭代器在第一个桶的第一个节点,当它遍历完该桶后,要怎么跳转到下一个有节点的桶?

此时传该哈希表的指针(即_pht)的意义就来了,有了该哈希表的指针,就可以遍历整个哈希表中所有的哈希桶,但要从哪开始遍历?程序怎么知道当前迭代器在哪个桶?

此时传KOfT和Hash的作用就来了,通过对当前迭代器的值除留余数法,就能算出当前迭代器在哪个桶,再去从该桶后面开始遍历即可

Self operator++()//前置++
{assert(_node);//防止节点本来就为空if (_node->_next)//如果该桶还有节点{_node = _node->_next;}else//该桶已被遍历完,需要找下一个桶{KOfT koft;//用于从T类型取出keysize_t index = _pht->HashFunc(koft(_node->_data)) % _pht->_table.size();//除留余数法取出映射index++;for (; index < _pht->_table.size())//从下一个桶开始找非空桶{Node* cur = _pht->_table[index];if (cur){_node = cur;return *this;//若找到,就直接返回本身迭代器}}_node = nullptr;//找不到就将迭代器置end()}return *this;
}Self operator++(int)//后置++
{Self tmp = *this;++*this;return tmp;
}

改造哈希表

 首先哈希表内部与迭代器支持一下

template<class K,class T,class KOfT,class Hash>//T可能是K或pair,KOfT是为了从T中取出key的仿函数,Hash是将不同类型的K转换为整型的仿函数
class HashTable
{typedef HashNode<T> Node;typedef typename __HashIterator<K, T, KOfT, Hash, T&, T*> iterator;typedef typename __HashIterator<K, T, KOfT, Hash, const T&, const T*> const_iterator;//只读迭代器friend iterator;//将只读和读写迭代器都变为友元,迭代器不管什么类型就都可以访问HashTable的_tablefriend const_iterator;
public:iterator begin(){for (size_t i = 0; i < _table.size(); i++){if (_table[i])return iterator(_table[i], this);//将第一个节点转换为迭代器}return end();}iterator end(){return nullptr;//这里就实现的简单点吧}const_iterator begin() const{for (size_t i = 0; i < _table.size(); i++){if (_table[i])return const_iterator(_table[i], this);//将第一个节点转换为迭代器}return end();}const_iterator end() const{return nullptr;}//.................
}

由于需要unordered_map需要支持operator[],因此需要先将原来的哈希表的Insert改造一下,返回值改为pair<iterator,bool>

pair<iterator,bool> Insert(const T& data)
{KOfT koft;//用于取出T类型的Keyif (_table.size() == _num)//负载因子到1时扩容{//1.开2倍大小空间(不一定是2倍)//2.遍历旧表数据,重新计算在新表中位置//3.释放旧表vector<Node*> newtable;size_t newsize = _table.size() ? _table.size() * 2 : 10;newtable.resize(newsize);for (auto& cur : _table){//将旧表中的节点取下来重新计算在新表中的位置,并插入进去Node* head = cur;while (head){Node* next = head->_next;size_t index = HashFunc(koft(head->_data)) % newtable.size();//头插进桶中head->_next = newtable[index];newtable[index] = head;head = next;}cur = nullptr;//将旧表该位置置空,否则最后析构旧表时就将节点都析构了}_table.swap(newtable);//旧表在出作用域后自动销毁}size_t index = HashFunc(koft(data)) % _table.size();//除留余数法取出映射//先查找值是否重复Node* cur = _table[index];while (cur){if (koft(cur->_data) == koft(data))//如果是重复值,插入失败return make_pair(iterator(cur,this),false);elsecur = cur->_next;}Node* newnode = new Node(data);//开辟新空间//头插到对应桶中(尾插也可以)newnode->_next = _table[index];_table[index] = newnode;_num++;return make_pair(iterator(newnode,this),true);
}

Find的返回值也改成迭代器

iterator Find(const K& key)
{KOfT koft;//用于取出T类型的keysize_t index = HashFunc(key) % _table.size();//算出映射//去该映射桶中找Node* cur = _table[index];while (cur){if (koft(cur->_data) == key)return iterator(cur,this);elsecur = cur->_next;}return iterator(nullptr,this);//找不到返回空
}

模拟实现unordered_map/unordered_set

和map/set时一样,只需要将哈希表套进去就可以

unordered_map

#pragma once
#include "HashTable.h"namespace valkyrie
{using namespace Open_Hash;template<class K,class V,class Hash = _Hash<K>>class unordered_map{struct KeyOfMap//用于从pair类型中取出K{const K& operator()(const pair<K, V>& kv){return kv.first;}};public:typedef typename HashTable<K, pair<K, V>, KeyOfMap, Hash>::iterator iterator;typedef typename HashTable<K, pair<K, V>, KeyOfMap, Hash>::const_iterator const_iterator;pair<iterator, bool> Insert(pair<K, V> kv){return _ht.Insert(kv);}iterator Find(const K& key){return _ht.Find(key);}bool Erase(const K& key){return _ht.Erase(key);}V& operator[](const K& key){pair<iterator, bool> pr = _ht.Insert(make_pair(key, V()));//不管插入失败还是成功,first中存的都是该Key的迭代器return pr.first->second;}iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}const_iterator begin() const{return _ht.begin();}const_iterator end() const{return _ht.end();}void clear(){_ht.clear();}private:HashTable<K, pair<K, V>, KeyOfMap, Hash> _ht;//哈希表作底层};}

unordered_set

#pragma once
#include "HashTable.h"namespace valkyrie
{using namespace Open_Hash;template<class K, class Hash = _Hash<K>>class unordered_set{struct KeyOfSet//为了适配KeyOfMap{const K& operator()(const K& key){return key;}};public:typedef typename HashTable<K, K, KeyOfSet, Hash>::iterator iterator;typedef typename HashTable<K, K, KeyOfSet, Hash>::const_iterator const_iterator;pair<iterator, bool> Insert(const K& key){return _ht.Insert(key);}iterator Find(const K& key){return _ht.Find(key);}bool Erase(const K& key){return _ht.Erase(key);}iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}const_iterator begin() const{return _ht.begin();}const_iterator end() const{return _ht.end();}void clear(){_ht.clear();}private:HashTable<K, K, KeyOfSet, Hash> _ht;//内部结构是哈希表};}

针对迭代器遍历的优化(思路)

在STL实现的unordered_map/unordered_set中,迭代器遍历的顺序就是插入数据的顺序,而目前我们自己实现的迭代器遍历是遍历桶来完成的,有没有什么办法可以完成像STL里的那种效果呢?

 我们可以在哈希表的节点结构中再加两个成员:_linknext和_linkprev

template<class T>
struct HashNode
{T _data;//K或KVHashNode* _next;//单链表HashNode* _linknext;//下一个插入的元素HashNode* _linkprev;//上一个插入的元素HashNode(const T& data)//默认构造,为下面的new HashNode而准备:_data(data), _next(nullptr){ }
};

 _linknext是为了遍历,_linkprev是为了在删除时可以找到上一个元素

虽然这样可以在遍历时按照插入的顺序,但这也会让哈希表的结构更加复杂.....这里就不作实现了

http://www.dtcms.com/wzjs/263477.html

相关文章:

  • 广告公司名字简单大气三个字淘宝seo是什么意思
  • 建设外卖网站规划书水果营销软文
  • 网站建设招标方案模板关键词排名是由什么决定的
  • 淘宝美工与网站开发搜索引擎调价工具哪个好
  • 企业网站源码 企业网站管理系统合肥网络推广
  • 抖音代运营合同模板免费系统优化软件十大排名
  • 自然人做音频网站违法吗泰安百度推广公司
  • 前端工程师主要做什么工作百度seo优化收费标准
  • 珠江摩尔网站建设太原seo培训
  • 网站上的高清图怎么做seort什么意思
  • 05网学霸答案怎么关闭seo综合查询
  • php网站方案产品推广计划怎么写
  • 安庆做网站的优化大师怎么卸载
  • 东明网站制作网站制作推广电话
  • 网站建设留言板的实现百家号seo怎么做
  • 电商网站建武汉百度百科
  • 自己做的网站能放到阿里云上网络营销app有哪些
  • 太仆寺旗党建网站建设5118站长网站
  • 深圳建设网站制作360搜索推广
  • 推广网站建设语句seo点击排名软件营销工具
  • h5可以连接别的网站吗怎么创建一个网址
  • 微信网站二次开发百度搜索资源平台官网
  • 外贸定制网站营销网站建设多少钱
  • 具有营销型网站的公司有哪些怎么查百度收录
  • 怎样更换网站cmsseo俱乐部
  • 免费申请网站永久域名怎么推广平台
  • 婚庆公司加盟seo顾问咨询
  • 做网站要找什么seo外链论坛
  • wordpress 插件 设计淘宝seo是指什么
  • 网站备案有哪些费用域名检测工具