十二、自己动手实现------------“ HashTable 哈希表 ”

博客给出Java数据结构和算法中哈希表相关参考文章,介绍哈希表核心思想是“用空间换时间”,查询操作基本达O(1)级别,还表示不讲解原理,直接给出代码主体部分。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考文章:

https://www.cnblogs.com/ysocean/p/8032656.html                     Java数据结构和算法(十三)——哈希表(强推

https://www.cnblogs.com/skywang12345/p/3310835.html           Java 集合系列10之 HashMap详细介绍(源码解析)和使用示例

https://github.com/liuyubobobo/Play-with-Algorithms  


       哈希表也是一种重要的数据结构,其核心思想是 “用空间换时间” ,其查询操作基本上能达到 O(1)  级别。哈希表的原理,上面两篇博客应该能够将的明明白白,代码部分参考 波波老师  的代码部分,写的是非常的优雅。

 

下面不讲原理,直接上代码主体部分:

import java.util.Map;
import java.util.TreeMap;

public class HashTable<K, V> {

    private static final int upperTol = 10;
    private static final int lowerTol = 2;
    private static final int initCapacity = 7;

    private TreeMap<K, V>[] hashtable;
    private int size;
    private int M;

    public HashTable(int M){
        this.M = M;
        size = 0;
        hashtable = new TreeMap[M];
        for(int i = 0 ; i < M ; i ++)
            hashtable[i] = new TreeMap<>();
    }

    public HashTable(){
        this(initCapacity);
    }

    private int hash(K key){
        return (key.hashCode() & 0x7fffffff) % M;
    }

    public int getSize(){
        return size;
    }

    public void add(K key, V value){
        TreeMap<K, V> map = hashtable[hash(key)];
        if(map.containsKey(key))
            map.put(key, value);
        else{
            map.put(key, value);
            size ++;

            if(size >= upperTol * M)
                resize(2 * M);
        }
    }

    public V remove(K key){
        V ret = null;
        TreeMap<K, V> map = hashtable[hash(key)];
        if(map.containsKey(key)){
            ret = map.remove(key);
            size --;

            if(size < lowerTol * M && M / 2 >= initCapacity)
                resize(M / 2);
        }
        return ret;
    }

    public void set(K key, V value){
        TreeMap<K, V> map = hashtable[hash(key)];
        if(!map.containsKey(key))
            throw new IllegalArgumentException(key + " doesn't exist!");

        map.put(key, value);
    }

    public boolean contains(K key){
        return hashtable[hash(key)].containsKey(key);
    }

    public V get(K key){
        return hashtable[hash(key)].get(key);
    }

    private void resize(int newM){
        TreeMap<K, V>[] newHashTable = new TreeMap[newM];
        for(int i = 0 ; i < newM ; i ++)
            newHashTable[i] = new TreeMap<>();

        int oldM = M;
        this.M = newM;
        for(int i = 0 ; i < oldM ; i ++){
            TreeMap<K, V> map = hashtable[i];
            for(K key: map.keySet())
                newHashTable[hash(key)].put(key, map.get(key));
        }

        this.hashtable = newHashTable;
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

<think>好的,我现在要帮用户解决如何实现哈希表代码的问题。首先,我需要回想用户之前的问题,他们之前问过哈希表在各类语言中的实现情况,现在他们可能想了解具体的代码实现方法。用户可能是刚开始学习数据结构,或者想在实际项目中自己实现一个哈希表。他们可能不太清楚哈希表的具体结构,或者对哈希函数、冲突处理这些概念不太熟悉。 接下来,我需要确定回答的结构。用户需要的是清晰的步骤和示例代码,可能还希望了解不同冲突处理方法。之前的回复中已经用Markdown展示了Python的实现示例,所以这次可能需要更详细地解释每个部分,比如哈希函数的选择、冲突处理机制,以及扩容策略。 用户可能对哈希表的基本原理有一定了解,但需要具体的代码指导。因此,我应该分步骤讲解,从哈希表的结构开始,到哈希函数的设计,再到冲突处理的方法,比如拉链法和开放寻址法。同时,示例代码需要简洁明了,方便用户理解。 我还需要考虑不同编程语言用户的背景,但用户的问题没有指定语言,所以可能需要用通用的伪代码或选择一种常见的语言,比如Python或Java。在之前的回答中,使用了Python示例,所以这次可以继续使用Python,并补充其他语言的例子或说明。 另外,用户可能对性能优化感兴趣,比如动态扩容的触发条件和实现方式。需要解释负载因子和扩容的关系,以及如何重新哈希。这部分内容对于实现一个高效的哈希表很重要,但初学者可能会忽略,所以需要简明扼要地说明。 还要注意潜在的问题,比如哈希函数的好坏对性能的影响,冲突处理方式的选择依据。可能需要给出一些常见的最佳实践,比如使用素数作为哈希表的大小,或者在拉链法中使用链表还是红黑树等结构。 最后,总结实现的关键点,帮助用户回顾重点,确保他们理解每一步的重要性。同时,提醒实际应用中可能需要注意的问题,比如线程安全或语言特有的优化策略。</think>--- ### 哈希表代码实现分步详解(Python示例) --- #### **1. 基本结构设计** 哈希表 = **数组 + 链表/开放寻址**,核心组件: ```python class HashTable: def __init__(self, capacity=10): self.capacity = capacity # 初始桶数量 self.size = 0 # 当前元素数量 self.buckets = [[] for _ in range(capacity)] # 桶数组(拉链法) ``` --- #### **2. 哈希函数** 将任意键转换为数组下标,常用方法: - **取模法**:`hash(key) % capacity` - **乘法散列**:`int(capacity * (hash(key) * 0.618 % 1))` ```python def _hash(self, key): # Python内置hash()处理不可变类型(字符串/数字/元组) return hash(key) % self.capacity ``` --- #### **3. 冲突处理**(两种主流方案) **方案一:拉链法(链式哈希)** - 每个桶用链表存储冲突元素 - 插入/查找时间复杂度:平均$O(1)$,最差$O(n)$ **插入操作代码**: ```python def put(self, key, value): index = self._hash(key) bucket = self.buckets[index] # 遍历链表检查是否已存在相同key for i, (k, v) in enumerate(bucket): if k == key: bucket[i] = (key, value) # 更新值 return bucket.append((key, value)) # 新增键值对 self.size += 1 ``` **查找操作代码**: ```python def get(self, key): index = self._hash(key) bucket = self.buckets[index] for k, v in bucket: if k == key: return v raise KeyError(f"Key {key} not found") ``` --- **方案二:开放寻址法** - 冲突时按规则探测下一个空位(线性探测/平方探测) - 需要维护标记区分空位和已删除位 ```python # 初始化时数组元素为None self.buckets = [None] * capacity # 线性探测插入 def put(self, key, value): index = self._hash(key) while self.buckets[index] is not None: if self.buckets[index][0] == key: self.buckets[index] = (key, value) # 更新 return index = (index + 1) % self.capacity # 向后探测 self.buckets[index] = (key, value) self.size += 1 ``` --- #### **4. 动态扩容** 当**负载因子(元素数/容量) > 阈值(通常0.75)**时触发扩容: 1. 新建2倍容量数组 2. 重新哈希所有元素到新数组 ```python def _resize(self): new_capacity = self.capacity * 2 new_buckets = [[] for _ in range(new_capacity)] # 遍历旧桶,重新计算哈希 for bucket in self.buckets: for key, value in bucket: new_index = hash(key) % new_capacity new_buckets[new_index].append((key, value)) self.capacity = new_capacity self.buckets = new_buckets ``` --- #### **5. 完整实现框架** ```python class HashTable: def __init__(self, capacity=10, load_factor=0.75): self.capacity = capacity self.load_factor = load_factor self.size = 0 self.buckets = [[] for _ in range(capacity)] def _hash(self, key): return hash(key) % self.capacity def put(self, key, value): if self.size / self.capacity > self.load_factor: self._resize() # ...插入逻辑(见上文)... def get(self, key): # ...查找逻辑(见上文)... def _resize(self): # ...扩容逻辑(见上文)... ``` --- ### **关键优化技巧** 1. **哈希函数选择**:避免聚集(如用质数作为模数) 2. **冲突处理对比**: - 拉链法:实现简单,适合频繁删除 - 开放寻址法:缓存更友好,但扩容更敏感 3. **扩容策略**:渐进式扩容(分批迁移,避免卡顿) --- ### **不同语言实现差异** - **Java**:`HashMap`使用链表转红黑树优化(当链表长度>8) - **Python**:`dict`采用开放寻址法+伪随机数探测 - **Go**:`map`底层是桶数组+溢出桶链表 --- **动手建议**:先用拉链法实现基础版,再逐步添加扩容和优化逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值