自己实现的hashmap

这是一个Java实现的MyHashMap类,遵循了MyMap接口。类中包含了初始化容量、负载因子的设置,以及哈希映射的相关方法,如put、get、containsKey、containsValue等。它使用LinkedList作为桶来存储键值对,并提供了重新哈希的功能以应对容量达到负载因子时的情况。

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

package com.dengpf.Lab;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;

/**
 * Created by kobe73er on 16/11/19.
 */
public class MyHashMap
   
   
    
     implements MyMap
    
    
     
      {


    private static int DEFAULT_INITAL_CAPACITY = 4;
    private static int MAXIMUM_CAPACITY = 1 << 30;

    private static float DEFAULT_MAX_LOAD_FACTOR = 0.75f;

    private int capacity = 0;

    private float loadFactor;

    private LinkedList
     
     
      
      
       
       >[] table;

    private int size = 0;

    public MyHashMap() {
        this(DEFAULT_INITAL_CAPACITY, DEFAULT_MAX_LOAD_FACTOR);
    }

    public MyHashMap(int capacity) {
        this(capacity, DEFAULT_MAX_LOAD_FACTOR);
    }

    public MyHashMap(int capacity, float loadFactor) {
        if (capacity > MAXIMUM_CAPACITY) {
            this.capacity = MAXIMUM_CAPACITY;
        } else {
            this.capacity = trimToPower(capacity);
        }

        table = new LinkedList[capacity];

        this.loadFactor = loadFactor;


    }

    private int trimToPower(int initialCapacity) {
        int capacitpy = 1;

        while (capacitpy < initialCapacity) {
            capacitpy <<= 1;
        }
        return capacitpy;
    }

    @Override
    public void clear() {
        size = 0;
        removeEntries();
    }

    /**
     * Remove all entries from each bucket
     */
    private void removeEntries() {
        for (int i = 0; i < capacity; i++) {
            if (table[i] != null) {
                table[i].clear();
            }
        }
    }

    @Override
    public boolean containsKey(K key) {
        if (get(key) != null) {
            return true;
        }
        return false;
    }

    @Override
    public boolean containsValue(V value) {
        for (int i = 0; i < capacity; i++) {
            if (table[i] != null) {
                LinkedList
       
        
        
          > bucket = table[i]; for (Entry 
         
           bucketItem : bucket) { if (bucketItem.getValue().equals(value)) { return true; } } } } return false; } @Override public boolean isEmpty() { return size == 0; } @Override public V get(K key) { int tableIndex = hash(key.hashCode()); if (table[tableIndex] != null) { LinkedList 
           
           
             > bucket = table[tableIndex]; for (Entry 
            
              entryItem : bucket) { if (entryItem.getKey().equals(key)) { return entryItem.getValue(); } } } return null; } /** * Hash function */ private int hash(int hashCode) { return supplementalHash(hashCode) & (capacity - 1); } /** * Ensure the hashing is evenly distributed */ private static int supplementalHash(int h) { h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); } @Override public V put(K key, V value) { if (null != get(key)) { int bucketIndex = hash(key.hashCode()); LinkedList 
              
              
                > bucket = table[bucketIndex]; for (Entry 
               
                 entryItem : bucket) { if (entryItem.getKey().equals(key)) { V oldVal = entryItem.getValue(); entryItem.setValue(value); return oldVal; } } } if (size() >= capacity * loadFactor) { if (capacity == MAXIMUM_CAPACITY) { throw new RuntimeException("Exceeding maximum capacity"); } reHash(); } if (table[hash(key.hashCode())] == null) { table[hash(key.hashCode())] = new LinkedList 
                 
                 
                   >(); } table[hash(key.hashCode())].add(new MyMap.Entry 
                  
                    (key, value)); size++; return value; } private void reHash() { java.util.Set 
                    
                    
                      > set = entrySet(); // Get entries capacity <<= 1; table = new LinkedList[capacity]; size = 0; for (Entry 
                     
                       entry : set) { put(entry.getKey(), entry.getValue()); // Store to new table } } @Override public int size() { return size; } @Override public Set 
                      
                        values() { Set 
                       
                         valueSet = new HashSet 
                        
                          (); for (int i = 0; i < capacity; i++) { if (table[i] != null) { LinkedList 
                          
                          
                            > bucket = table[i]; for (Entry 
                           
                             entry : bucket) valueSet.add(entry.getValue()); } } return valueSet; } @Override public Set 
                            
                              keySet() { java.util.Set 
                             
                               set = new java.util.HashSet 
                              
                                (); for (int i = 0; i < capacity; i++) { if (table[i] != null) { LinkedList 
                                
                                
                                  > bucket = table[i]; for (Entry 
                                 
                                   entry : bucket) set.add(entry.getKey()); } } return set; } @Override public void remove(K key) { int bucketIndex = key.hashCode(); if (null != table[bucketIndex]) { LinkedList 
                                   
                                   
                                     > bucket = table[bucketIndex]; for (Entry 
                                    
                                      entryItem : bucket) { if (entryItem.getKey().equals(key)) { bucket.remove(); size--; break; } } } } @Override public Set 
                                      
                                      
                                        > entrySet() { Set 
                                        
                                        
                                          > entrySet = new HashSet 
                                          
                                          
                                            >(); for (int i = 0; i < capacity; i++) { if (table[i] != null) { LinkedList 
                                            
                                            
                                              > bucket = table[i]; for (Entry 
                                             
                                               entryItem : bucket) { entrySet.add(entryItem); } } } return entrySet; } } 
                                              
                                             
                                            
                                           
                                          
                                         
                                        
                                       
                                      
                                     
                                    
                                   
                                  
                                 
                                
                               
                              
                             
                            
                           
                          
                         
                        
                       
                      
                     
                    
                   
                  
                 
                
               
              
             
            
           
          
         
       
      
      
     
     
    
    
   
   
<think>好的,用户想了解如何在C语言中实现一个HashMap。我需要先回忆HashMap的基本概念和结构。HashMap通常由数组和链表(或红黑树)组成,处理冲突的方法有开放寻址和链地址法。C语言没有内置的哈希表,所以需要手动实现。 首先,确定哈希表的结构。每个节点应该包含键、值和指向下一个节点的指针,处理冲突用链地址法。然后定义哈希表的结构,包括容量、大小和存储桶数组。 接下来,哈希函数的选择。可能用简单的取模运算,或者更复杂的如djb2算法。这里可能需要考虑哈希函数的分布均匀性。 然后,需要实现基本的操作:插入、查找、删除。插入时要处理冲突,可能需要动态扩容,但用户可能暂时不需要太复杂的扩容机制,先实现基础版本。 还要考虑内存管理,特别是节点的创建和释放。需要确保没有内存泄漏,比如在删除节点时正确释放内存。 可能用户会关心如何处理不同的数据类型,但C语言中通常用void指针来支持泛型,但会增加复杂性。可能需要先实现固定类型的键值,比如字符串键和整型值,简化示例。 最后,测试代码,验证各个功能是否正常。比如插入几个键值对,然后查找和删除,确保正确性。 需要提醒用户注意哈希表容量选择为质数,减少哈希冲突。另外,动态扩容的阈值和策略,比如负载因子超过0.75时扩容,但可能在基础实现中暂不处理,保持简单。 可能用户是初学者,所以代码示例要清晰,结构明确,避免复杂的优化,重点放在核心逻辑上。同时解释每一步的作用,确保用户能够理解每个函数的功能和实现方法。</think>在C语言中实现HashMap需要手动处理内存和数据结构,以下是分步实现说明: --- ### 一、HashMap核心结构 ```c #define DEFAULT_CAPACITY 16 // 初始容量(建议使用质数) #define LOAD_FACTOR 0.75 // 扩容阈值 // 哈希节点结构 typedef struct HashNode { char* key; // 键(字符串示例) int value; // 值 struct HashNode* next; // 链表解决冲突 } HashNode; // HashMap主体结构 typedef struct { HashNode** buckets; // 存储桶数组 int capacity; // 总容量 int size; // 当前元素数 } HashMap; ``` --- ### 二、关键函数实现 #### 1. 哈希函数 ```c // 使用djb2算法(高效字符串哈希) unsigned long hash_func(const char* key, int capacity) { unsigned long hash = 5381; int c; while ((c = *key++)) { hash = ((hash << 5) + hash) + c; // hash * 33 + c } return hash % capacity; } ``` #### 2. 创建HashMap ```c HashMap* hashmap_create() { HashMap* map = (HashMap*)malloc(sizeof(HashMap)); map->capacity = DEFAULT_CAPACITY; map->size = 0; map->buckets = (HashNode**)calloc(DEFAULT_CAPACITY, sizeof(HashNode*)); return map; } ``` #### 3. 插入键值对 ```c void hashmap_put(HashMap* map, const char* key, int value) { // 计算桶索引 unsigned long index = hash_func(key, map->capacity); // 检查键是否存在 HashNode* current = map->buckets[index]; while (current) { if (strcmp(current->key, key) == 0) { current->value = value; // 更新值 return; } current = current->next; } // 创建新节点 HashNode* newNode = (HashNode*)malloc(sizeof(HashNode)); newNode->key = strdup(key); // 深拷贝键 newNode->value = value; newNode->next = map->buckets[index]; // 头插法 map->buckets[index] = newNode; map->size++; } ``` #### 4. 查找键值 ```c int hashmap_get(HashMap* map, const char* key, int* found) { unsigned long index = hash_func(key, map->capacity); HashNode* current = map->buckets[index]; while (current) { if (strcmp(current->key, key) == 0) { *found = 1; return current->value; } current = current->next; } *found = 0; return -1; // 未找到的返回值 } ``` #### 5. 删除键值 ```c void hashmap_remove(HashMap* map, const char* key) { unsigned long index = hash_func(key, map->capacity); HashNode* current = map->buckets[index]; HashNode* prev = NULL; while (current) { if (strcmp(current->key, key) == 0) { if (prev) { prev->next = current->next; } else { map->buckets[index] = current->next; } free(current->key); free(current); map->size--; return; } prev = current; current = current->next; } } ``` --- ### 三、使用示例 ```c int main() { HashMap* map = hashmap_create(); // 插入数据 hashmap_put(map, "apple", 42); hashmap_put(map, "banana", 17); // 查找数据 int found; int val = hashmap_get(map, "apple", &found); if (found) printf("apple的值: %d\n", val); // 删除数据 hashmap_remove(map, "banana"); // 释放内存(需实现hashmap_destroy) return 0; } ``` --- ### 四、优化方向 1. **动态扩容**:当`size/capacity > LOAD_FACTOR`时,新建更大的桶数组并重新哈希 2. **红黑树优化**:当链表长度超过阈值(如8)时,转换为红黑树(类似Java HashMap) 3. **泛型支持**:使用`void*`实现任意类型键值 4. **线程安全**:添加互斥锁实现并发访问 --- ### 五、注意事项 - 内存管理需严格对应:每个`malloc`必须有对应的`free` - 字符串键建议使用`strdup`深拷贝,避免外部修改 - 哈希函数的选择直接影响性能,需根据数据类型优化 完整实现代码约200行,需要处理更多边界条件。建议参考开源项目(如Redis字典实现)获取生产级方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值