每日一省之————利用数组和链表实现一个简单的HashMap

今天本人想要复习的是哈希表(散列表)的概念及具体实现,为此用java写了一个简单的实现,但仅仅只是实现了一些简单的功能,不过通过这个简单的实现的确可以帮助我们进一步理解JDK中的HashMap,当然,想要进一步了解就直接阅读JDK中的HashMap的源码啦。

实现代码如下,有注释,本人就不进一步阐述了:

/**
 * 该类是HashMap的一个简单实现。
 * 
 * 这里,我主要采用一个元素是链表的数组来模拟JDK中的HashMap实现。 当存入一个键值对(K,V)的时候,首先计算键(K)对应的HashCode。这个HashCode的值其实就是具体实现过程中用到的数组的索引。通过计算键的HashCode值便可以知道应该将键值对(K,V)存储在第几个数组元素中。如前所述,每一个数组元素其实又是一个链表。将键值对存入散列表其实是存入底层数组元素对应的链表结构中。之所以使用链表作为数组元素是为了避免HashCode相同但又不相等的键造成冲突时候相互覆盖的问题。这样就很好的解决了可能存在的碰撞冲突问题。
 * 
 * @author lhever
 *
 * @param <K>
 * @param <V>
 */
public class SimpleHashMap<K, V> {
    public static final int INITIAL_CAPACITY = 4;

    private int N;
    private int M;
    private SequentialST<K, V>[] table;

    /**
     * 构造
     */
    public SimpleHashMap() {
        this(INITIAL_CAPACITY);
    }

    /**
     * 构造,可以指定底层数组的大小
     * 
     * @param M
     */
    public SimpleHashMap(int M) {
        this.M = M;
        table = (SequentialST<K, V>[]) new SequentialST[M];
        for (int i = 0; i < M; i++) {
            table[i] = new SequentialST<K, V>();
        }

    }

    /**
     * 重新调整底层数组的大小,从实现的角度看,所有已经 存入的键值对会被从新计算散列值并调整存储的位置。
     * 
     * @param newSize
     */
    private void resize(int newSize) {
        SimpleHashMap<K, V> temp = new SimpleHashMap<K, V>(newSize);
        for (int i = 0; i < M; i++) {
            for (K key : table[i].keys()) {
                temp.put(key, table[i].get(key));
            }
        }
        this.M = temp.M;
        this.N = temp.N;
        this.table = temp.table;
    }

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

    public int size() {
        return N;
    }

    public boolean isEmpty() {
        return size() == 0;
    }

    public boolean contains(K key) {
        if (key == null) {
            throw new NullPointerException("参数不能为null");
        }
        return get(key) != null;
    }

    public V get(K key) {
        if (key == null) {
            throw new NullPointerException("参数不能为null");

        }
        int i = hash(key);
        return table[i].get(key);
    }

    public void put(K key, V val) {
        if (key == null) {
            throw new NullPointerException("key不能为null");
        }
        if (val == null) {
            remove(key);
            return;
        }

        // 当链表中的平均元素个数大于10的时候增加底层数组的大小(变为两倍大)
        if (N >= 10 * M) {
            resize(2 * M);
        }

        int i = hash(key);
        if (!table[i].contains(key)) {
            N++;
        }
        table[i].put(key, val);
    }

    public void remove(K key) {
        if (key == null) {
            throw new NullPointerException("参数不能为null");
        }

        int i = hash(key);
        if (table[i].contains(key)) {
            N--;
            table[i].delete(key);
        }

        // 如果列表中的平均元素个数小于等于2的时候,降低底层数组的大小(变为原来大小的1/2)
        if (M > INITIAL_CAPACITY && N <= 2 * M) {
            resize(M / 2);
        }
    }

    // 返回一个迭代器,其中包含了所有的键
    public Iterable<K> keys() {
        Queue<K> queue = new LinkedList<K>();
        for (int i = 0; i < M; i++) {
            for (K key : table[i].keys())
                queue.offer(key);
        }
        return (Iterable<K>) queue;
    }

    /**
     * 测试
     * 
     * @param args
     */
    public static void main(String... args) {

        SimpleHashMap map = new SimpleHashMap<String, String>();

        map.put("country", "China");
        map.put("level", "super");
        map.put("nature", "public");

        System.out.println(map.get("country"));
        System.out.println("befor remove, the size is: " + map.size());
        map.remove("country");
        System.out.println("after remove, the size is: " + map.size());

        for (String key : (Iterable<String>) map.keys()) {
            System.out.println(key + " : " + map.get(key));
        }

        map.remove("nature");
        map.remove("level");
        map.remove("level");
        System.out.println("after remove, the size is: " + map.size());

        for (String key : (Iterable<String>) map.keys()) {
            System.out.println(key + " : " + map.get(key));
        }

        map.put("size", "960");
        System.out.println("after put, the size is: " + map.size());
    }

}




package lhever.Hash_Map;

import java.util.LinkedList;
import java.util.Queue;

/**
 * 该类是一个顺序查找的链表实现,查找元素时候会从第一个节点开始顺序查找,
 * 该链表实现会被用到SimpleHashMap(JDK中HashMap的一个简单实现)的实现中
 * 
 * @author lhever
 *
 * @param <K>
 * @param <V>
 */
public class SequentialST<K, V> {
    private int N;
    private Node first;

    /**
     * 代表一个节点
     * 
     * @author lhever
     */
    private class Node {

        private K key;
        private V value;
        private Node next;

        public Node(K key, V value, Node next) {
            this.key = key;
            this.value = value;
            this.next = next;
        }

    }

    public SequentialST() {

    }

    public int size() {
        return N;
    }

    public boolean isEmpty() {
        return size() == 0;
    }

    public boolean contains(K key) {
        if (key == null)
            throw new NullPointerException("参数不能为null");
        return get(key) != null;
    }

    /**
     * 查找从第一个节点开始顺序进行
     * 
     * @param key
     * @return
     */
    public V get(K key) {
        if (key == null)
            throw new NullPointerException("参数不能为null");
        for (Node node = first; node != null; node = node.next) {
            if (key.equals(node.key))
                return node.value;
        }
        return null;
    }

    /**
     * 增加
     * 
     * @param key
     * @param value
     */
    public void put(K key, V value) {
        if (key == null)
            throw new NullPointerException("参数不能为null");
        if (value == null) {
            delete(key);
            return;
        }

        for (Node node = first; node != null; node = node.next) {
            if (key.equals(node.key)) {
                node.value = value;
                return;
            }
        }
        first = new Node(key, value, first);
        N++;
    }

    public void delete(K key) {
        if (key == null)
            throw new NullPointerException("参数不能为null");
        first = delete(first, key);
    }

    private Node delete(Node node, K key) {
        if (node == null)
            return null;
        if (key.equals(node.key)) {
            N--;
            return node.next;
        }
        node.next = delete(node.next, key);
        return node;
    }

    public Iterable<K> keys() {
        Queue<K> queue = new LinkedList<K>();
        for (Node node = first; node != null; node = node.next)
            queue.offer(node.key);
        return queue;
    }

}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值