每日一省之————利用数组和链表实现一个简单的HashMap
2016-09-03 15:54
489 查看
今天本人想要复习的是哈希表(散列表)的概念及具体实现,为此用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; } }
相关文章推荐
- 用 Python实现链表的翻转,奇偶下标修改(利用数组,非常简单)
- 利用模板实现简单的栈类(数组和单链表)
- linux网络编程二十一:利用SIGALRM信号,实现一个简单的基于升序链表的定时器
- Structure.Hash(通过数组和链表实现一个简单的Hash)
- 根据数组+链表的原理,自己实现一个简易版的HashMap
- 每日一省之—使用线性探测法(仅利用数组作为底层数据结构)实现HashMap
- 利用数组和链表实现简单的哈希表
- HashMap实现原理,利用数组和链表存储元素
- 用UDP实现可靠文件传输,如何利用UDX创建一个简单的WIN32程序
- 利用Compass实现一个简单的搜索引擎
- 利用Compass实现一个简单的搜索引擎
- 【Android游戏开发十六】Android Gesture之【触摸屏手势识别】操作!利用触摸屏手势实现一个简单切换图片的功能!
- 一个简单的链表的实现
- C语言实现一个简单的单向链表list
- 利用java实现一个简单的远程监控程序
- 利用boost::asio实现一个简单的服务器框架
- 利用 Axis 实现一个简单的 Web Serive例子
- 转载的标准文档:C语言实现一个简单的单向链表list
- 一个简单的HashMap C语言实现
- 利用java实现一个简单的远程监控程序