STL hashtable阅读记录

unordered_map,unordered_set等相关内容总结:
unordered_map和unordered_set是在开发过程中常见的stl数据结构。其本质是hashtable。在SGI_STL中,hashtable解决冲突的办法是拉链法。下面是一些对STL中堆hashtable中有关代码阅读的一些记录。
与之相关联的几个文件 
gcc/ libstdc++-v3/ include/ bits/hashtable.h
gcc/ libstdc++-v3/ include/ bits/hashtable_policy.h
gcc/ libstdc++-v3/ include/ bits/functional_hash.h
gcc/ libstdc++-v3/ src/ c++11/hashtable_c++0x.cc
 
 
 
第一部分:基本数据组织说明
hashtable的重要数据组织成员及辅助理解图(一个可能的hash数据结构情况)
_Bucket[] _M_buckets
_Hash_node_base _M_before_begin
size_type _M_bucket_count // 初始桶编号为1
size_type _M_element_count

 

 
 
由上图可以大致总结出在SGI-STL中hashtable数据的组织。几个要点:
①.hashtable实际上是维护了一个单链标。其头节点是一个特殊的成员_M_before_begin,其没有实际的数据。按照名字来理解,是第一个数据的前一个节点。
看一下对应的相关注释:
The non-empty buckets contain the node before the first node,this design makes it possible to implement somethiing like a std::forward_list::insert_after on a container insertion and std::forward_list::erase_afer on container erase calls._M_before_begin is equivalent to  std::forward_list_list::before_begin.Note that one of the non-empty buckets contains &_M_before_begin which is not a dereferenceable node so  the node pointer ina bucket shall never be dereferenced ,only its next node can be.
②._M_buckets这个二级指针的作用是什么,其目的是为了通用的可以使用_M_next()函数调用拿到每个桶的头节点(对于上图就是A,D)。比如_M_buckets[1]._M_next就是桶号为1的头结点A。_M_buckets[2]._M_next就是桶号为2的数据结构的头结点D。同时对于上图示例,应当有_M_before_begin和_M_buckets[1]是相等的(见黑色实线)
 
 
第二部分:几个常见接口的调用流程及调用栈
hashtable的定义

 

 
一些方便查阅的 using和typedef

 

 

 

①.插入的key是如何生成的
    1.对于简单类型(int等):key计算的相关代码 const key_type& __k = this->_M_extract()(__node->_M_v())
    计算key值是通过_M_extrace()来计算的,其是模板参数中的_ExtraceKey,
   对于unordered_map在其定义中其模板参数中_ExtraceKey是__detail::Select1st 当定义为unordered_map<int,node>,insert(std::make_pair(0,node(a)); 其就返回pair中的first,即0。
   对于如果定义类似于key不是简单类型的。需要自己定义hash函数否则不能通过编译,举例 https://www.zhihu.com/question/30921173
    
struct pairhash {public:
template <typename T, typename U>
std::size_t operator()(const std::pair<T, U> &x) const
{
    return std::hash<T>()(x.first) ^ std::hash<U>()(x.second);
}};
class abc {
    std::unordered_map<std::pair<int,int>, int, pairhash> rules;
};
在这种情况下。__detail::Select1st获取到的数据就是std::pair<int,int>作为key对应的值
②.hash值如何生成
 __hash_code __code = this->_M_hash_code(__key);   ======> return _M_h1()(__k);  ======> 在key为int的时候传递的参数是std::hash<int> 
其最后会调用一个宏_Cxx_hashtable_define_trivial_hash(int),其在文件functional_hash.h中,该文件内涵多种不同类型的特化hash类。该文件定义了这些简单类型是如何hash的,下面是该宏的定义,看到这种情况下,其hash值就是直接强转成size_t类型。

 

 
③.如何确定一对pair的hash桶编号    size_type __bkt = _M_bucket_index(__k,__code) ====> return ___hash_code_base::_M_bucket_index(__k,__c,_M_bucket_count); } ====> return _M_h2()(__c,__n);    
    其中_M_h2获取的是模板参数_H2,对于unordered_map传递进来的是__detail::_Mod_range_hashing,其内容很简单。

 

可见桶编号值为hash值mod桶数量
④.rehash流程:主要思路是根据当前桶的数量和元素数量,在一个大的素数表中lowerbound查找下一步合适的桶编号。
下面是一个判定是否需要rehash桶以及如果需要后算出下一个合理的桶数量。至于最终的真正_M_rehash_aux流程。主题是数据指针迁移,并且保证新的new_buckets结构像前图一样。
 
 
 
 
 
 

 

 
 
 
 
 
 
 

转载于:https://www.cnblogs.com/Commence/p/9057364.html

### 使用 C++ STL 哈希表读取文件的方法 在 C++ 中,可以利用 `unordered_map` 和其他相关容器来实现基于哈希表的文件读取功能。以下是具体方法和实现细节: #### 1. 文件读取基础 C++ 提供了标准输入输出流(如 `ifstream`),用于从文件中读取数据[^1]。可以通过逐行或按特定分隔符解析的方式提取所需的信息。 #### 2. 数据存储方式 为了高效地查找和管理数据,可以选择使用 `std::unordered_map` 来作为哈希表的核心工具。该容器允许以键值对的形式存储数据,并支持平均时间复杂度为 O(1) 的快速查找操作[^3]。 #### 3. 实现代码示例 下面是一个完整的代码示例,展示如何使用 C++ STL 哈希表 (`unordered_map`) 来读取并处理 STL 格式的文件内容: ```cpp #include <iostream> #include <fstream> #include <string> #include <unordered_map> int main() { std::string filename = "data.stl"; // 输入文件名 std::ifstream file(filename); if (!file.is_open()) { std::cerr << "无法打开文件!" << std::endl; return -1; } std::unordered_map<std::string, int> hashTable; // 创建哈希表 std::string line; while (getline(file, line)) { // 按行读取文件 // 对每行进行简单预处理,例如去除空白字符 line.erase(std::remove_if(line.begin(), line.end(), ::isspace), line.end()); // 如果当前行为有效,则将其存入哈希表 if (!line.empty()) { auto it = hashTable.find(line); // 查找是否存在此条目 if (it != hashTable.end()) { ++(it->second); // 若已存在则计数加一 } else { hashTable[line] = 1; // 否则新增记录 } } } file.close(); // 关闭文件 // 输出哈希表中的所有项及其频率 for (const auto& pair : hashTable) { std::cout << "Key: " << pair.first << ", Count: " << pair.second << std::endl; } return 0; } ``` 上述代码实现了以下功能: - 打开指定名称的 `.stl` 文件。 - 遍历每一行的内容,并移除多余的空格或其他无关字符。 - 将非空的有效行插入到 `unordered_map` 中,其中键表示唯一的字符串,而值代表其出现次数。 - 最终打印出整个哈希表内的全部键值对[^2]。 #### 4. 处理冲突的情况 当发生哈希碰撞时,即多个不同的键被映射到了同一个位置上,`unordered_map` 自动采用链地址法解决这一问题。此时访问某个特定元素的时间性能会退化至最坏情况下的线性级别 O(N)。然而,在实际应用过程中,由于良好的散列函数设计以及动态调整负载因子机制的存在,这种情况很少见。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值