每日一省之————利用数组和链表实现一个简单的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
- 每日一省之————利用数组和链表实现一个简单的HashMap
- 每日一省之—使用线性探测法(仅利用数组作为底层数据结构)实现HashMap
- 每日一省之 ———— 一个简单的跳跃表(Skip List)的Java实现
- 每日一省————链表之栈的简单实现
- 每日一省————链表之队列的简单实现
- 每日一题(41)—— 数组和链表的区别
- 每日一省之————递归法计算数组的所有排列组合
- HashMap实现原理,利用数组和链表存储元素
- 每日一省之—基于双数组和二分查找法实现符号表(或者字典)
- 每日一题(33)——用两个栈实现一个队列的功能?要求给出算法和思路
- 每日一省之————红黑树的java实现
- 利用数组和链表实现简单的哈希表
- 每日一题(42)—— 已知一个数组table,用一个宏定义,求出数据的元素个数
- iOS每日一记————————简单的实现委托 Block代码块 功能 和简单的自定义View
- iOS每日一记——————之简单的去重操作。。。。
- iOS每日一记之——————————基于Socket的简单封装和使用
- 每日一题——实现取最小值的栈
- 每日一题——memcpy,strcpy,memmove的实现
- IIS应用程序池服务停止如何解决
- oracle的JDBC使用preparedStatement处理char类型字段的问题
- CDH5.8安装说明
- NHibernate使用入门(十三)
- 浅析总结 Android Studio 中 Gradle 配置运行
- 每日一省之————利用数组和链表实现一个简单的HashMap
- 常见的java面试题和答案
- 南阳ACM 第5题 BinaryMatch KMP算法实现
- uva11181 Probability|Given
- 自定义保存session路径
- escape()、encodeURI()、encodeURIComponent()区别详解
- jQuery设计思想
- javaweb学习总结(三十四)——使用JDBC处理MySQL大数据
- 数据结构之栈迷宫求解