黄山游玩攻略及费用黔南seo
2026/1/2 12:51:50 网站建设 项目流程
黄山游玩攻略及费用,黔南seo,做网站个人备案,中小企业网站建设济南兴田德润电话可扩展哈希#xff08;Extendible Hashing#xff09;详解一、传统哈希的问题1.1 传统哈希扩容的痛苦c// 传统链地址法哈希表扩容 void rehash(hashtable* table) {// 1. 分配新桶数组#xff08;通常翻倍#xff09;// 2. 重新计算所有元素的哈希值// 3. 迁移所有数据到新…可扩展哈希Extendible Hashing详解一、传统哈希的问题1.1 传统哈希扩容的痛苦c// 传统链地址法哈希表扩容 void rehash(hashtable* table) { // 1. 分配新桶数组通常翻倍 // 2. 重新计算所有元素的哈希值 // 3. 迁移所有数据到新数组 // 问题扩容时所有数据都要移动O(n)时间复杂度 }扩容代价数据量大时扩容卡顿扩容期间服务可能不可用内存瞬间翻倍二、可扩展哈希的核心思想2.1 核心目标渐进式扩容每次只扩容一点点而不是全部重来2.2 目录Directory的作用text想象一下你有一本电话号码本目录 1. 目录不是直接存储数据而是存储指向桶的指针 2. 每个桶是一个固定大小的容器 3. 当某个桶满了只分裂这个桶不影响其他桶三、数据结构设计解析3.1 为什么需要Bucket结构体c// 传统链地址法每个桶是一个链表 hashnode** buckets; // 桶数组每个元素是链表头 // 可扩展哈希每个桶是一个固定大小的数组 typedef struct bucket { int local_depth; // 这个桶的局部深度关键 int count; // 当前元素数量 hash_node* entries[BUCKET_CAPACITY]; // 固定大小的数组 } bucket;对比特性传统链地址法桶可扩展哈希桶大小动态链表固定数组冲突解决链表链接分裂桶扩容粒度整个表单个桶3.2 为什么需要Directoryc// 传统哈希直接访问桶 index hash(key) % capacity; bucket buckets[index]; // 直接访问 // 可扩展哈希通过目录访问 index hash(key) ((1 global_depth) - 1); // 取低global_depth位 bucket directory[index]; // 通过目录找到桶目录的作用间接寻址目录指向桶多个目录项可以指向同一个桶平滑扩容分裂桶时只需要更新部分目录指针减少数据迁移只迁移被分裂桶的数据四、深度Depth的概念4.1 全局深度Global Depthcint global_depth; // 目录的大小 2^global_depth整个哈希表的精度决定使用哈希值的多少位目录大小 2^global_depth4.2 局部深度Local Depthctypedef struct bucket { int local_depth; // 这个桶的精度 // ... } bucket;每个桶有自己的深度决定这个桶对应哈希值的多少位local_depth ≤ global_depth4.3 深度示例text假设哈希值: 10101101 (二进制) 全局深度 2 使用低2位: 01 (十进制1) 目录索引 1 桶的局部深度 2 这个桶负责所有以01结尾的哈希值五、工作流程详解5.1 初始状态text全局深度 1 目录大小 2^1 2 两个目录项都指向同一个桶 目录[0] -- 桶A (局部深度1) 目录[1] -- 桶A (局部深度1)5.2 插入数据桶未满text插入 key1 (哈希值...0) - 目录[0] - 桶A 插入 key2 (哈希值...1) - 目录[1] - 桶A 桶A: [key1, key2]5.3 桶分裂当桶满时text桶A已满假设容量2需要插入key3 key3的哈希值以0结尾 - 目录[0] - 桶A 分裂过程 1. 创建两个新桶桶B(深度2), 桶C(深度2) 2. 重新分配桶A的数据 - 以00结尾的 - 桶B - 以10结尾的 - 桶C 3. 更新目录 目录[00] 桶B 目录[10] 桶C 目录[01] 桶A (保持不变) 目录[11] 桶A 为什么局部深度1的桶可以同时被多个目录项指向 因为哈希值的低1位相同都是1的数据都应该去同一个桶5.4 目录倍增当局部深度全局深度时text如果桶的local_depth global_depth需要倍增目录 倍增前 全局深度 1 目录: [0]-桶A, [1]-桶A 倍增后 全局深度 2 目录: [00]-桶A, [01]-桶A, [10]-桶A, [11]-桶A六、为什么没有负载因子6.1 传统哈希的负载因子c// 传统哈希用负载因子触发扩容 if ((double)size / capacity LOAD_FACTOR) { rehash(); // 全部扩容 }6.2 可扩展哈希的触发机制c// 可扩展哈希不需要全局负载因子 // 每个桶独立判断是否需要分裂 if (bucket-count BUCKET_CAPACITY) { split_bucket(bucket); // 只分裂这个桶 }优势局部性只有热点桶才分裂精准扩容不浪费内存无全局停顿扩容不影响其他桶的访问七、可视化示例7.1 初始状态text全局深度: 1 目录大小: 2 目录: [0] -- 桶A (局部深度:1, 数据: 空) [1] -- 桶A 插入 apple(hash...0), banana(hash...1) 后 桶A: [apple, banana]7.2 桶分裂text插入 orange(hash...0)桶A已满容量2 分裂后 全局深度: 2 目录大小: 4 目录: [00] -- 桶B (局部深度:2, 数据: [apple]) [01] -- 桶A (局部深度:1, 数据: [banana]) [10] -- 桶C (局部深度:2, 数据: [orange]) [11] -- 桶A 注意目录[01]和[11]都指向桶A因为它们哈希值的低1位都是1八、性能分析8.1 时间复杂度text操作 时间复杂度 说明 查找 O(1) 一次目录访问桶内查找 插入 O(1) 可能触发分裂但分摊O(1) 删除 O(1) 分裂 O(B) B是桶容量只移动一个桶的数据 目录倍增 O(2^d) 指数级但很少发生8.2 空间复杂度text目录: O(2^global_depth) 指针 数据: O(n) 实际元素 比传统哈希多了一个目录的空间开销九、适用场景9.1 适合的场景数据库索引B树的替代支持范围查询文件系统ext2/ext3的目录索引内存受限环境避免一次性大扩容实时系统需要保证响应时间9.2 不适合的场景小数据量目录开销太大频繁删除不容易合并桶内存敏感目录占用额外空间十、与传统哈希的对比特性传统链地址法可扩展哈希扩容方式全表rehash桶分裂扩容代价O(n)O(桶容量)空间开销较小目录桶查找速度O(1)平均O(1)删除支持容易较复杂合并内存使用可能浪费更精准十一、代码关键点解释c// 1. 计算索引使用哈希值的低global_depth位 int index hash(key) ((1 global_depth) - 1); // 2. 桶分裂创建两个新桶深度1 bucket* new_bucket1 create_bucket(old_depth 1); bucket* new_bucket2 create_bucket(old_depth 1); // 3. 重新分配根据哈希值的第old_depth1位分配 int new_index hash ((1 (old_depth 1)) - 1); if (new_index original_index) { // 去新桶1 } else { // 去新桶2兄弟桶 } // 4. 目录更新更新所有指向旧桶的目录项 int step 1 (old_depth 1); for (int i original_index; i dir_size; i step) { directory[i] new_bucket1; } for (int i buddy_index; i dir_size; i step) { directory[i] new_bucket2; }十二、总结可扩展哈希通过目录桶的二级结构实现了渐进式扩容目录提供间接寻址允许平滑扩容桶固定大小的容器满时分裂深度控制哈希值的使用位数无全局负载因子每个桶独立管理核心优势扩容时只移动一个桶的数据避免了传统哈希的全表rehash特别适合大规模、高并发的场景。代价需要额外的目录空间实现比传统哈希复杂。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询