【C++进阶】哈希(万字详解)—— 学习篇(上)

02-29 阅读 0评论

🎇C++学习历程:入门

【C++进阶】哈希(万字详解)—— 学习篇(上),【C++进阶】哈希(万字详解)—— 学习篇(上),词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,使用,我们,访问,第1张
(图片来源网络,侵删)

  • 博客主页:一起去看日落吗
  • 持续分享博主的C++学习历程
  • 博主的能力有限,出现错误希望大家不吝赐教
  • 分享给大家一句我很喜欢的话: 也许你现在做的事情,暂时看不到成果,但不要忘记,树🌿成长之前也要扎根,也要在漫长的时光🌞中沉淀养分。静下来想一想,哪有这么多的天赋异禀,那些让你羡慕的优秀的人也都曾默默地翻山越岭🐾。

    【C++进阶】哈希(万字详解)—— 学习篇(上)

    🍁 🍃 🍂 🌿


    目录

    • 🍁 1. unordered系列关联式容器
      • 🍂 1.1 unordered_map
        • 🍃 1.1.1 unordered_map的文档介绍
        • 🍃 1.1.2 unordered_map的接口说明
        • 🍃 1.1.3 unordered_set的文档介绍
        • 🍃 1.1.4 unordered_map和unordered_set的使用
        • 🍂 1.2 在线OJ
        • 🍁 2. 底层结构
          • 🍂 2.1 哈希概念
          • 🍂 2.2 哈希冲突
          • 🍂 2.3 哈希函数
          • 🍂 2.4 哈希冲突解决
            • 🍃 2.4.1 闭散列
            • 🍃 2.4.2 闭散列的实现
            • 🍃 2.4.3 开散列
            • 🍃 2.4.4 开散列的实现

              🍁 1. unordered系列关联式容器

              在C++98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到 l o g 2 N log_2 N log2​N,即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查询效率也不理想。最好的查询是,进行很少的比较次数就能够将元素找到,因此在C++11中,STL又提供了4个unordered系列的关联式容器,这四个容器与红黑树结构的关联式容器使用方式基本类似,只是其底层结构不同,本文中只对unordered_map和unordered_set进行介绍,

              unordered_multimap和unordered_multiset学生可查看文档介绍。

              map和set底层是红黑树实现的,map是KV模型,set是K模型,而unordered_map和unordered_set底层是哈希表实现的,unordered_set是K模型,unordered_map是KV模型

              【C++进阶】哈希(万字详解)—— 学习篇(上)

              unordered_map和unordered_set的命名体现特点,在功能和map/set是一样的,区别在于,它遍历出来是无序的,另外,它们的迭代器是单向迭代器

              【C++进阶】哈希(万字详解)—— 学习篇(上),【C++进阶】哈希(万字详解)—— 学习篇(上),词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,使用,我们,访问,第4张
              (图片来源网络,侵删)

              🍂 1.1 unordered_map

              🍃 1.1.1 unordered_map的文档介绍

              unordered_map在线文档说明

              1. unordered_map是存储键值对的关联式容器,其允许通过keys快速的索引到与其对应的value。
              2. 在unordered_map中,键值通常用于惟一地标识元素,而映射值是一个对象,其内容与此键关联。键

                映射值的类型可能不同。

              3. 在内部,unordered_map没有对按照任何特定的顺序排序, 为了能在常数范围内找到key所对应的value,unordered_map将相同哈希值的键值对放在相同的桶中。
              4. unordered_map容器通过key访问单个元素要比map快,但它通常在遍历元素子集的范围迭代方面效率较低。
              5. unordered_maps实现了直接访问操作符(operator[]),它允许使用key作为参数直接访问value。
              6. 它的迭代器至少是前向迭代器。

              🍃 1.1.2 unordered_map的接口说明

              • unordered_map的构造
                函数声明功能介绍
                unordered_map构造不同格式的unordered_map对象
                • unordered_map的容量
                  函数声明功能介绍
                  bool empty() const检测unordered_map是否为空
                  size_t size() const获取unordered_map的有效元素个数
                  • unordered_map的迭代器
                    函数声明功能介绍
                    begin返回unordered_map第一个元素的迭代器
                    end返回unordered_map最后一个元素下一个位置的迭代器
                    cbegin返回unordered_map第一个元素的const迭代器
                    cend返回unordered_map最后一个元素下一个位置的const迭代器
                    • unordered_map的元素访问
                      函数声明功能介绍
                      operator[]返回与key对应的value,没有一个默认值

                      注意:该函数中实际调用哈希桶的插入操作,用参数key与V()构造一个默认值往底层哈希桶中插入,如果key不在哈希桶中,插入成功,返回V(),插入失败,说明key已经在哈希桶中,将key对应的value返回。

                      • unordered_map的查询
                        函数声明功能介绍
                        iterator find(const K& key)返回key在哈希桶中的位置
                        size_t count(const K& key)返回哈希桶中关键码为key的键值对的个数

                        注意:unordered_map中key是不能重复的,因此count函数的返回值最大为1

                        • unordered_map的修改操作
                          函数声明功能介绍
                          insert向容器中插入键值对
                          erase删除容器中的键值对
                          void clear()清空容器中有效元素个数
                          void swap(unordered_map&)交换两个容器中的元素
                          • unordered_map的桶操作
                            函数声明功能介绍
                            size_t bucket_count()const返回哈希桶中桶的总个数
                            size_t bucket_size(size_t n)const返回n号桶中有效元素的总个数
                            size_t bucket(const K& key)返回元素key所在的桶号

                            🍃 1.1.3 unordered_set的文档介绍

                            unordered_set的在线文档介绍


                            🍃 1.1.4 unordered_map和unordered_set的使用

                            • unordered_set
                              #include
                              #include
                              #include
                              using namespace std;
                              void test_unordered_set()
                              {
                                  unordered_set s;
                                  s.insert(3);
                                  s.insert(4);
                                  s.insert(5);
                                  s.insert(3);
                                  s.insert(1);
                                  s.insert(2);
                                  s.insert(6);
                                  unordered_set::iterator it = s.begin();
                                  while (it != s.end())
                                  {
                                      cout 
                                  test_unordered_set();
                                  return 0;
                              }
                              
                                  unordered_map
                                      cout 
                                  test_unordered_map();
                                  return 0;
                              }
                              
                              public:
                                  int repeatedNTimes(vector
                                      size_t N = nums.size() / 2;
                                      unordered_map
                                          if(e.second == N)
                                              return e.first;
                                      }
                                      return 0;
                                  }
                              };
                              
                              public:
                                  vector
                                      // 用unordered_set对nums1中的元素去重
                                      unordered_set
                                          if (s2.find(e) != s2.end())
                                              vRet.push_back(e);
                                      }
                                      return vRet;
                                  }
                              };
                              
                              public:
                                  vector
                                      if (nums1.size()  nums2.size()) {
                                          return intersect(nums2, nums1);
                                      }
                                      unordered_map 
                                          ++m[num];
                                      }
                                      vector
                                          if (m.count(num)) {
                                              intersection.push_back(num);
                                              --m[num];
                                              if (m[num] == 0) {
                                                  m.erase(num);
                                              }
                                          }
                                      }
                                      return intersection;
                                  }
                              };
                              
                              public:
                                  bool containsDuplicate(vector
                                      unordered_set
                                          if (s.find(x) != s.end()) {
                                              return true;
                                          }
                                          s.insert(x);
                                      }
                                      return false;
                                  }
                              };
                              
                              public:
                                  vector
                                      unordered_map
                                          stringstream ss(s);
                                          string word;
                                          while (ss  word) {
                                              ++freq[move(word)];
                                          }
                                      };
                                      insert(s1);
                                      insert(s2);
                                      vector
                                          if (occ == 1) {
                                              ans.push_back(word);
                                          }
                                      }
                                      return ans;
                                  }
                              };
                              
                                  enum Status
                                  {
                                      EMPTY,//空
                                      EXIST,//存在
                                      DELETE//删除
                                  };
                                  template
                                      pair
                                      size_t operator()(const K&key)
                                      {
                                          return key;
                                      }
                                  };    
                                  //特化
                                  template
                                      size_t operator()(const string& key)
                                      {
                                          //BKDR Hash思想
                                          size_t hash = 0;
                                          for(size_t i = 0;i
                                              hash*=131;
                                              hash += key[i];//转成整形
                                          }
                                          return hash;
                                      }
                                  };  
                                  template
                                  public:
                                      bool Erase(const K& key)
                                      {
                                          HashData
                                              //没有这个值
                                              return false;
                                          }
                                          else
                                          {
                                              //伪删除
                                              ret-_status = DELETE;
                                              _n--;
                                              return true;
                                          }
                                      }
                                      HashData
                                          if(_table.size() == 0)
                                          {
                                              //防止除0错误
                                              return nullptr;
                                          }
                                          Hash hf;
                                          size_t index = hf(key) % _table.size();
                                          size_t i = 0;
                                          size_t index = start + i;
                                          while(_tables[index]._status != EMPTY)
                                          {
                                              if(_tabled[index]._kv.first == key && _table[index]._status == EXIST)
                                              {
                                                  return &_tabled[index];
                                              }
                                              else
                                              {
                                                  ++i;
                                                  //index = start+i;//线性探测
                                                  index = start+i*i;//二次探测
                                                  index %= _tables.size();
                                              }
                                          }
                                          return nullptr;
                                      }
                                      //插入
                                      bool Insert(const pair
                                          if(Find(kv.first))
                                          {
                                              return false;
                                          }
                                          if(_table.size() == 0 || (double)(_n / _table.size())  0.7)
                                          {
                                              //扩容
                                              //方法二:
                                              size_t newSize = _table.size()==0? 10 : _table.size()*2;
                                              HashTable
                                                  if(e._status == EXIST)
                                                  {
                                                      newHT.Insert(e._kv);//将旧表的数据插入新表
                                                  }
                                              }
                                              _table.swap(newHT._tables);//将新表和旧表交换
                                          }
                                          Hash hf;
                                          size_t start = hf(kv.first) % _tables.size();
                                          //线性探测
                                          size_t i = 0;
                                          size_t index = start + i;
                                          while(_table[index]._status == EXIST)
                                          {
                                              ++index;
                                              if(index == _tables.size())
                                              {
                                                  //当index到达最后的时候,让它回到起始
                                                  index = 0;
                                              }
                                              //插满的时候会死循环
                                          }
                                          //走到这里要么是空要么是删除
                                          _tables[index]._kv = kv;
                                          _tables[index]._status = EXIST;
                                          ++_n;
                                          
                                          return true;
                                      }
                                  private:
                                      vector
                              	template
                              		pair}
                              	};
                              	size_t GetNextPrime(size_t prime)
                              	{
                              		const int PRIMECOUNT = 28;
                              		static const size_t primeList[PRIMECOUNT] =
                              		{
                              			53ul, 97ul, 193ul, 389ul, 769ul,
                              			1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
                              			49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
                              			1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul,
                              			50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,
                              			1610612741ul, 3221225473ul, 4294967291ul
                              		};
                              		size_t i = 0;
                              		for (; i _kv.first == key)
                              				{
                              					// 1、cur是头结点
                              					// 2、非头节点
                              					if (prev == nullptr)
                              					{
                              						_tables[index] = cur->_next;
                              					}
                              					else
                              					{
                              						prev->_next = cur->_next;
                              					}
                              					delete cur;
                              					--_n;
                              					return true;
                              				}
                              				else
                              				{
                              					prev = cur;
                              					cur = cur->_next;
                              				}
                              			}
                              			return false;
                              		}
                              		Node* Find(const K& key)
                              		{
                              			if (_tables.size() == 0)
                              			{
                              				return nullptr;
                              			}
                              			Hash hf;
                              			size_t index = hf(key) % _tables.size();
                              			Node* cur = _tables[index];
                              			while (cur)
                              			{
                              				if (cur->_kv.first == key)
                              				{
                              					return cur;
                              				}
                              				else
                              				{
                              					cur = cur->_next;
                              				}
                              			}
                              			return nullptr;
                              		}
                              		bool Insert(const pair& kv)
                              		{
                              			Hash hf;
                              			//当负载因子到1时,进行扩容
                              			if (_n == _tables.size())
                              			{
                              				//size_t newSize = _tables.size() == 0 ? 10 : _tables.size() * 2;
                              				size_t newSize = GetNextPrime(_tables.size());
                              				//HashTable newHT;
                              				vector newtables;
                              				newtables.resize(newSize, nullptr);
                              				for (size_t i = 0; i _next;
                              						size_t index = hf(cur->_kv.first) % newSize;
                              						cur->_next = newtables[index];
                              						newtables[index] = cur;
                              						cur = next;
                              					}
                              					_tables[i] = nullptr;
                              				}
                              				newtables.swap(_tables);
                              			}
                              			size_t index = hf(kv.first) % _tables.size();
                              			Node* cur = _tables[index];
                              			while (cur)
                              			{
                              				if (cur->_kv.first == kv.first)
                              				{
                              					return false;
                              				}
                              				else
                              				{
                              					cur = cur->_next;
                              				}
                              			}
                              			Node* newnode = new Node(kv);
                              			newnode->_next = _tables[index];
                              			_tables[index] = newnode;
                              			++_n;
                              			return true;
                              		}
                              	private:
                              		vector _tables;
                              		size_t _n = 0; // 存储多少有效数据
                              	};
                                  
                              


免责声明
本网站所收集的部分公开资料来源于AI生成和互联网,转载的目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

发表评论

快捷回复: 表情:
评论列表 (暂无评论,人围观)

还没有评论,来说两句吧...

目录[+]