📜  循环哈希映射 - Java (1)

📅  最后修改于: 2023-12-03 14:54:15.641000             🧑  作者: Mango

循环哈希映射 - Java

简介

循环哈希映射是一种可以实现持续增长的键值对集合的数据结构。不同于传统的哈希表只能存储固定大小的键值对,循环哈希映射通过动态的调整内部存储结构,能够存储更多的数据,并且保持高效的查询和更新操作。

在循环哈希映射中,键通过哈希函数转换成一个整数,然后将整数映射到一个哈希表中的位置。哈希表由一个固定大小的数组组成,数组中的每个元素是一个链表,用于解决哈希冲突。当键值对的数量超过哈希表大小时,循环哈希映射会自动进行扩容,重新计算各个键值对的哈希值,并将它们重新映射到新的哈希表中。

功能

循环哈希映射提供以下功能:

  • 插入键值对:通过指定键和值,将键值对插入到循环哈希映射中。
  • 删除键值对:通过指定键,从循环哈希映射中删除对应的键值对。
  • 获取值:通过指定键,获取对应的值。
  • 更新值:通过指定键和新的值,更新对应键的值。
  • 判断键是否存在:通过指定键,判断对应的键值对是否存在于循环哈希映射中。
数据结构

循环哈希映射的主要数据结构包括:

  • 内部哈希表:用于存储键值对的数组。每个数组元素都是一个链表,用于解决哈希冲突。
  • 哈希函数:用于将键转换为整数,并映射到内部哈希表中的位置。
  • 扩容策略:当键值对数量超过内部哈希表大小时,触发扩容操作,重新计算哈希值,并将键值对重新映射到新的哈希表中。
示例代码
/**
 * 循环哈希映射的实现
 */
public class MyHashMap {
    private static final int INITIAL_CAPACITY = 16; // 初始哈希表大小
    private static final double LOAD_FACTOR = 0.75; // 负载因子,用于判断是否需要扩容

    private Entry[] table; // 内部哈希表
    private int size; // 键值对数量

    /**
     * 哈希映射的条目
     */
    private static class Entry {
        private final int key;
        private Object value;
        private Entry next;

        public Entry(int key, Object value) {
            this.key = key;
            this.value = value;
        }
    }

    /**
     * 构造函数,创建循环哈希映射
     */
    public MyHashMap() {
        table = new Entry[INITIAL_CAPACITY];
        size = 0;
    }

    /**
     * 通过键获取对应的值
     *
     * @param key 键
     * @return 值,如果键不存在返回null
     */
    public Object get(int key) {
        int index = getIndex(key);
        Entry entry = table[index];

        // 遍历链表查找键值对
        while (entry != null) {
            if (entry.key == key) {
                return entry.value;
            }
            entry = entry.next;
        }

        return null; // 键不存在
    }

    /**
     * 插入键值对
     *
     * @param key   键
     * @param value 值
     */
    public void put(int key, Object value) {
        int index = getIndex(key);
        Entry entry = table[index];

        // 遍历链表查找键值对
        while (entry != null) {
            if (entry.key == key) {
                entry.value = value; // 更新值
                return;
            }
            entry = entry.next;
        }

        // 创建新的条目,并插入到链表头部
        Entry newEntry = new Entry(key, value);
        newEntry.next = table[index];
        table[index] = newEntry;

        size++;

        // 判断是否需要进行扩容
        if ((double) size / table.length > LOAD_FACTOR) {
            resizeTable();
        }
    }

    /**
     * 删除键值对
     *
     * @param key 键
     */
    public void remove(int key) {
        int index = getIndex(key);
        Entry entry = table[index];
        Entry prev = null;

        // 遍历链表查找键值对
        while (entry != null) {
            if (entry.key == key) {
                if (prev != null) {
                    prev.next = entry.next; // 删除当前节点
                } else {
                    table[index] = entry.next; // 删除表头节点
                }
                size--;
                return;
            }
            prev = entry;
            entry = entry.next;
        }
    }

    /**
     * 判断键是否存在
     *
     * @param key 键
     * @return 如果键存在返回true,否则返回false
     */
    public boolean containsKey(int key) {
        int index = getIndex(key);
        Entry entry = table[index];

        // 遍历链表查找键值对
        while (entry != null) {
            if (entry.key == key) {
                return true;
            }
            entry = entry.next;
        }

        return false; // 键不存在
    }

    /**
     * 获取哈希值对应的索引位置
     *
     * @param key 键
     * @return 哈希值对应的索引位置
     */
    private int getIndex(int key) {
        return Math.abs(key) % table.length;
    }

    /**
     * 扩容操作,重新计算各个键值对的哈希值,并根据新的哈希值重新映射到新的哈希表中
     */
    private void resizeTable() {
        Entry[] oldTable = table;
        table = new Entry[oldTable.length * 2];
        size = 0;

        // 遍历旧的哈希表,重新映射到新的哈希表中
        for (Entry entry : oldTable) {
            while (entry != null) {
                put(entry.key, entry.value);
                entry = entry.next;
            }
        }
    }
}

以上是一个简单的循环哈希映射的Java代码实现。使用该类可以方便地插入、删除、获取和更新键值对,并可以高效地处理大量数据。哈希函数和扩容策略的设计可以根据需求进行调整,以满足特定的场景。