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

怎么用dw做响应式网站网店推广目的

怎么用dw做响应式网站,网店推广目的,wordpress dms,北京西城区建设网站文章目录📖 前言1. 复用同一个哈希桶⚡1.1 🌀修改后结点的定义1.2 🌀两个容器各自模板参数类型:2. 改造之后的哈希桶⛳3. 哈希桶的迭代器🔥3.1 💥哈希桶的begin()和 end(…

文章目录

  • 📖 前言
  • 1. 复用同一个哈希桶⚡
    • 1.1 🌀修改后结点的定义
    • 1.2 🌀两个容器各自模板参数类型:
  • 2. 改造之后的哈希桶⛳
  • 3. 哈希桶的迭代器🔥
    • 3.1 💥哈希桶的begin()和 end()的定义
    • 3.2 💥 operator* 和 operator->
    • 3.3 💥 operator++
    • 3.4 💥 operator== 和 operator!=
  • 4. 封装unordered_map和unordered_set⭕

📖 前言

与学习红黑树和map、set的思路一样,我们在学unordered_map和unordered_set时,也是先学底层结构,在用模拟的底层结构来自己封装一下该容器,动手实践来让我们更好的学习和理解底层逻辑。

前情回顾:哈希桶 👉 传送门

这里用到的封装思路和封装map、set的思路相同,都是更高维度的泛型编程。

思路复习:封装map和set 👉 传送门


1. 复用同一个哈希桶⚡

如何复用同一个哈希桶,我们就需要对哈希桶进行改造,将哈希桶改造的更加泛型一点,既符合Key模型,也符合Key_Value模型。

1.1 🌀修改后结点的定义

在这里插入图片描述
所以我们这里还是和封装map和set时一样,无论是Key还是Key_Value,都用一个类型T来接收,这里高维度的泛型哈希表中,实现还是用的是Kye_Value模型,K是不能省略的,同样的查找和删除要用。

1.2 🌀两个容器各自模板参数类型:

在这里插入图片描述
如何取到想要的数据:

  • 我们给每个容器配一个仿函数
  • 各传不同的仿函数,拿到想要的不同的数据

同时我们再给每个容器配一个哈希函数。

2. 改造之后的哈希桶⛳

//K --> 键值Key,T --> 数据
//unordered_map ->HashTable<K, pair<K, V>, MapKeyOfT> _ht;
//unordered_set ->HashTable<K, K, SetKeyOfT> _ht;
template<class K, class T, class KeyOfT, class HashFunc>
class HashTable
{template<class K, class T, class KeyOfT, class HashFunc>friend class __HTIterator;typedef HashNode<T> Node;
public:typedef __HTIterator<K, T, KeyOfT, HashFunc> iterator;iterator begin(){for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];if (cur){return iterator(cur, this);}}return end();}iterator end(){return iterator(nullptr, this);}~HashTable(){for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];while (cur){Node* next = cur->_next;delete cur;cur = next;}_tables[i] = nullptr;}}size_t GetNextPrime(size_t prime){const int PRIMECOUNT = 28;static const size_t primeList[PRIMECOUNT] ={53,         97,         193,       389,       769,1543,       3079,       6151,      12289,     24593,49157,      98317,      196613,    393241,    786433,1572869,    3145739,    6291469,   12582917,  25165843,50331653,   100663319,  201326611, 402653189, 805306457,1610612741, 3221225473, 4294967291};//获取比prime大那一个素数size_t i = 0;for (i = 0; i < PRIMECOUNT; i++){if (primeList[i] > prime)return primeList[i];}return primeList[i];}pair<iterator, bool> Insert(const T& data){HashFunc hf;KeyOfT kot;iterator pos = Find(kot(data));if (pos != end()){return make_pair(pos, false);}//负载因子 == 1 扩容 -- 平均每个桶挂一个结点if (_tables.size() == _n){//size_t newSize = _tables.size() == 0 ? 10 : _tables.size() * 2;size_t newSize = GetNextPrime(_tables.size());if (newSize != _tables.size()){vector<Node*> newTable;newTable.resize(newSize, nullptr);//遍历旧表for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];//再对每个桶挨个遍历while (cur){Node* next = cur->_next;size_t hashi = hf(kot(cur->_data)) % newSize;//转移到新的表中cur->_next = newTable[hashi];newTable[hashi] = cur;cur = next;}//将原表置空_tables[i] = nullptr;}newTable.swap(_tables);}}size_t hashi = hf(kot(data));hashi %= _tables.size();//头插到对应的桶即可Node* newnode = new Node(data);newnode->_next = _tables[hashi];_tables[hashi] = newnode;//有效数据加一_n++;return make_pair(iterator(newnode, this), true);}iterator Find(const K& key){if (_tables.size() == 0){return iterator(nullptr, this);}KeyOfT kot;HashFunc hf;size_t hashi = hf(key);//size_t hashi = HashFunc()(key);hashi %= _tables.size();Node* cur = _tables[hashi];//找到指定的桶之后,顺着单链表挨个找while (cur){if (kot(cur->_data) == key){return iterator(cur, this);}cur = cur->_next;}//没找到返回空return iterator(nullptr, this);}bool Erase(const K& key){if (_tables.size() == 0){return false;}HashFunc hf;KeyOfT kot;size_t hashi = hf(key);hashi %= _tables.size();//单链表删除结点Node* prev = nullptr;Node* cur = _tables[hashi];while (cur){if (kot(cur->_data) == key){//头删if (prev == nullptr){_tables[hashi] = cur->_next;}else{prev->_next = cur->_next;}delete cur;return true;}prev = cur;cur = cur->_next;}return false;}
private://指针数组vector<Node*> _tables;size_t _n = 0;
};

研究表明:除留余数法,最好模一个素数

  • 通过查STL官方库我们也发现,其提供了一个取素数的函数
  • 所以我们也提供了一个,直接拷贝过来
    • 这样我们在扩容时就可以每次给素数个桶
    • 在扩容时加了一条判断语句是为了防止素数值太大,过分扩容容易直接把空间(堆)干崩了

3. 哈希桶的迭代器🔥

3.1 💥哈希桶的begin()和 end()的定义

在这里插入图片描述

  • 以第一个桶中第一个不为空的结点为整个哈希桶的开始结点
  • 以空结点为哈希桶的结束结点

3.2 💥 operator* 和 operator->

在这里插入图片描述
同之前operator->的连续优化一样,不再赘述……

3.3 💥 operator++

在这里插入图片描述
备注:

  • 这里要在哈希桶的类外面访问其私有成员
  • 我们要搞一个友元类
  • 迭代器类是哈希桶类的朋友
  • 这样就可以访问了

在这里插入图片描述

思路:

  • 判断一个桶中的数据是否遍历完
    • 如果所在的桶没有遍历完,在该桶中返回下一个结点指针
    • 如果所在的桶遍历完了,进入下一个桶
  • 判断下一个桶是否为空
    • 非空返回桶中第一个节点
    • 空的话就遍历一个桶

后置++和之前一眼老套路,不赘述

注意:

  • unordered_map和unordered_set是不支持反向迭代器的,从底层结构我们也能很好的理解(单链表找不了前驱)
  • 所以不支持实现迭代器的operator- -

3.4 💥 operator== 和 operator!=

在这里插入图片描述

template<class K, class T, class KeyOfT, class HashFunc>
class HashTable;//哈希桶的迭代器
template<class K, class T, class KeyOfT, class HashFunc>
class __HTIterator
{typedef HashNode<T> Node;typedef __HTIterator<K, T, KeyOfT, HashFunc> Self;
public:Node* _node;__HTIterator() {};//编译器的原则是向上查找(定义必须在前面,否则必须先声明)HashTable<K, T, KeyOfT, HashFunc>* _pht;__HTIterator(Node* node, HashTable<K, T, KeyOfT, HashFunc>* pht):_node(node), _pht(pht){}Self& operator++(){if (_node->_next){ _node = _node->_next;}else//当前桶已经走完了,要走下一个桶{KeyOfT kot;HashFunc hf;size_t hashi = hf(kot(_node->_data)) % _pht->_tables.size();hashi++;//找下一个不为空的桶 -- 访问到了哈希表中私有的成员(友元)for (; hashi < _pht->_tables.size(); hashi++){if (_pht->_tables[hashi]){_node = _pht->_tables[hashi];break;}}//没有找到不为空的桶,用nullptr去做end标识if (hashi == _pht->_tables.size()){_node = nullptr;}}return *this;}T& operator*(){return _node->_data;}T* operator->(){return &_node->_data;}bool operator!=(const Self& s) const{return _node != s._node;}bool operator==(const Self& s) const{return _node == s._node;}
};

在这里插入图片描述
编译器的原则是向上查找(定义必须在前面,否则必须先声明)


4. 封装unordered_map和unordered_set⭕

有了上面的哈希桶的改装,我们这里的对map和set的封装就显得很得心应手了。

unordered_map的封装:

template<class K, class V, class HashFunc = DefaultHash<K>>
class unordered_map
{struct MapKeyOfT{const K& operator()(const pair<K, V>& kv){return kv.first;}};
public:typedef typename Bucket::HashTable<K, pair<K, V>, MapKeyOfT, HashFunc>::iterator iterator;iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}pair<iterator, bool> insert(const 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> ret = insert(make_pair(key, V()));return ret.first->second;}private:Bucket::HashTable<K, pair<K, V>, MapKeyOfT, HashFunc> _ht;
};

这里unordered_map中的operator[ ]我们知道其原理之后,模拟实现就非常方便,直接调用插入函数,控制好参数和返回值即可。

对unordered_set的封装:

template<class K, class HashFunc = DefaultHash<K>>
class unordered_set
{//SteKeyOfT是set专用的就用内部类struct SetKeyOfT{const K& operator()(const K& key){return key;}};public:typedef typename Bucket::HashTable<K, K, SetKeyOfT, HashFunc>::iterator iterator;iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}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);}
private:Bucket::HashTable<K, K, SetKeyOfT, HashFunc> _ht;
};
http://www.yayakq.cn/news/378517/

相关文章:

  • 做网站的难题化妆品网站建设可行性报告
  • 网站开发系统设计成都网站建设平台
  • 牛网站企业网站建站的专业性原则是指网站信息内容应该体现建站目的和目标群体
  • 那个网站教你做毕设的网页设计动态效果怎么制作
  • 什么网站做弹窗广告好wordpress站点搬家
  • 小型的做网站公司从哪里接的项目免费查看采购信息的平台
  • 美发培训网站管理咨询公司企业简介
  • 做网站的时候表格怎么去掉河北省网站建设
  • 萝岗做网站中国十大购物商场排名
  • 兰州网站设计制作如何把做的网站发布到网上
  • 东莞微信网站建设品牌无锡网站广优化公司
  • 网站还没上线怎么做品牌推广营销型网站建设明细报
  • 山东省工程建设招标信息网站360建网站好不好?
  • 鑫三科技网站设计河南省机场集团
  • 国内好的企业网站c2c交易是什么意思
  • 网站建设 有聊天工具的吗官方网站哪家做的最好
  • 东莞网站制作哪家公司好上海娱乐场所最新规定
  • 怎么学习制作网站上海建筑信息平台
  • 内蒙古建网站泰州专业制作网站
  • app开发人员网站怎样制作灯笼
  • 临近做网站优化网络培训
  • 一 网站建设的总体目标做网站的网站犯法吗
  • 邢台网站建设报价深圳网站建设制作营销
  • 网站名查询东莞做网站设计制作
  • 网站 一般 用什么空间大岭山仿做网站
  • 东莞市网站推广哪个地方可学习网站建设
  • 保定设计网站html5 国外网站
  • 登录建设银行网站打不开wordpress登陆卡
  • 经典的网站设计工具wordpress linux迁移
  • 网站界面设计缺点怎么做微信网站