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

来源:互联网 发布:钱夫人雪梨淘宝图片 编辑:程序博客网 时间:2024/05/02 04:44

今天本人想要复习的是哈希表(散列表)的概念及具体实现,为此用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;    }}
0 0