重温数据结构:哈希表,MyHashMap与MyHashSet的Java实现
来源:互联网 发布:官方软件 编辑:程序博客网 时间:2024/06/06 14:07
一.哈希表的相关概念
哈希函数的构造方法:
1. 直接定址法
2. 数字分析法
3. 平法取中法
4. 折叠法
5. 除留余数法
6. 随机数法
二.处理冲突的方法
1. 开放定制法(线性探测再散列、二次探测再散列、伪随机探测再散列)
2. 再哈希法
3. 链地址法
4. 建立一个公共溢出区
三.MyHashMap的实现
要点:哈希函数的方法选用“除留余数法”,处理冲突的方法是用“链地址法”,也即是当发生冲突时,凡是哈希地址为i的记录,都插入到头指针为tables[i]的链表中,插入的位置可以是表头,也可以是表尾,也可以在中间(以保持key的有序)。
本次实现的MyHashMap是将其插入表头。
package edu.njupt.zhb;/* *@author: ZhengHaibo *web: http://blog.csdn.net/nuptboyzhb *mail: zhb931706659@126.com *2014-3-25 Nanjing,njupt,China */public class MyHashMap<K,V>{/** * HashMap数组中的节点 * @param <K> * @param <V> */public class MyEntry<K,V>{ public K key;//键 public V value;//值 public MyEntry<K,V> next;//下一个结点}private MyEntry<K, V> []tables;private final int INIT_LEN=50;public MyHashMap() {tables=new MyEntry[INIT_LEN];}/** * 哈希函数的构造方法:除留余数法 * @param hashcode * @return */public int indexFor(int hashcode){return Math.abs(hashcode)%tables.length;}/** * 获取键为key的值 * @param key * @return */public V get(K key){if(key==null){return null;}int hashcode=key.hashCode();//计算键的哈希值int index=indexFor(hashcode);//根据哈希值计算其在表中的下标indexMyEntry<K, V> pNode=tables[index];//取出第一个节点,也即是链表的头//在链表中查找while(pNode!=null){//对链表进行遍历//当key的哈希值和真实值相等时返回if(pNode.key.hashCode()==hashcode&&(key==pNode.key || key.equals(pNode.key))){return pNode.value;}pNode=pNode.next;//链表:遍历下一个值}return null;}/** * 将键值对放入map当中 * 解决冲突的方法:链地址法 * @param key * @param value * @return */public V put(K key,V value){if(key==null){return null;}int hashcode=key.hashCode();int index=indexFor(hashcode);MyEntry<K, V> head=tables[index];//取出第一个节点,也即是链表的头MyEntry<K, V> pNode=head;//首先查找是否已经存在keywhile(pNode!=null){//当key的哈希值和真实值相等时if(pNode.key.hashCode()==hashcode&&(key==pNode.key || key.equals(pNode.key))){pNode.value=value;//更新当前key的值return pNode.value;}pNode=pNode.next;//链表:遍历下一个值}//如果没有查找到,将该值插入到链表的表头MyEntry<K, V> newNode=new MyEntry<K,V>();newNode.key=key;newNode.value=value;newNode.next=head;tables[index]=newNode;return value;}/** * 根据key删除对应的值 * 思路:先查找,后删除 * @param key * @return */public V remove(K key){if(key==null){return null;}int hashcode=key.hashCode();int index=indexFor(hashcode);MyEntry<K, V> head=tables[index];MyEntry<K, V> pNode=head;if(pNode==null){return null;}//表头if(pNode.key.hashCode()==hashcode&&(key==pNode.key || key.equals(pNode.key))){V value=pNode.value;tables[index]=pNode.next;//删除头节点return value;}//首先查找是否已经存在keywhile(pNode.next!=null){//当key的哈希值和真实值相等时if(pNode.next.key.hashCode()==hashcode&&(key==pNode.next.key || key.equals(pNode.next.key))){V value=pNode.value;pNode.next=pNode.next.next;//删除该节点return value;}pNode=pNode.next;//链表:遍历下一个值}return null;}public void print(){for(int i=0;i<tables.length;i++){MyEntry<K, V> entry=tables[i];if(entry!=null){while(entry!=null){System.out.println("key="+entry.key+",value="+entry.value);entry=entry.next;}}}}/** * 测试 * @param args */public static void main(String[] args) {MyHashMap<String, String> map=new MyHashMap<String, String>();for(int i=0;i<100;i++){map.put("stu"+i, ""+i);}for(int i=0;i<20;i++){map.remove("stu"+i);}map.print();}}
四.MyHashSet的实现
思路:和HashMap的思路一样,我们也是先计算hash值,然后折算出位置index,然后进行插入或删除。查找元素的效率很高,不需要对所有元素进行比较。
package edu.njupt.zhb;/* *@author: ZhengHaibo *web: http://blog.csdn.net/nuptboyzhb *mail: zhb931706659@126.com *2014-3-25 Nanjing,njupt,China */public class MyHashSet<T>{/** * 节点 */public class MyEntry<T>{public T data;//当前数据public MyEntry<T> next;}private MyEntry<T> []tables;//数组private final int INIT_LEN=50;private int size;public MyHashSet(){tables=new MyEntry[INIT_LEN];size=0;}/** * 哈希函数构造方法 * @param hashcode 哈希值 * @return 对应的数组下标 */private int indexFor(int hashcode){return Math.abs(hashcode)%tables.length;}/** * 添加元素 * @param object * @return */public boolean add(T data){if(data==null){return false;}int hashcode=data.hashCode();//计算哈希值int index=indexFor(hashcode);//定位存储的位置MyEntry<T> head=tables[index];//取出该位置的第一个元素(链表的头)MyEntry<T> pNode=head;//查找链表中是否存在while(pNode!=null){if(pNode.data.hashCode()==hashcode&&(pNode.data==data||pNode.data.equals(data))){return false;//已经存在重复的元素}pNode=pNode.next;}//不存在重复的元素或该位置为空,将该节点添加到链表的头MyEntry<T> newNode=new MyEntry<T>();newNode.data=data;newNode.next=head;tables[index]=newNode;size++;return true;}public boolean remove(T data){if(data==null){return false;}int hashcode=data.hashCode();int index=indexFor(hashcode);MyEntry<T> head=tables[index];MyEntry<T> pNode=head;if(pNode.data.hashCode()==hashcode&&(pNode.data==data||pNode.data.equals(data))){tables[index]=pNode.next;size--;return true;}while(pNode.next!=null){if(pNode.next.data.hashCode()==hashcode&&(pNode.next.data==data||pNode.next.data.equals(data))){pNode.next=pNode.next.next;//删除该元素size--;return true;}pNode=pNode.next;}return false;}public void print(){for(int i=0;i<tables.length;i++){MyEntry<T> entry=tables[i];if(entry!=null){while(entry!=null){System.out.println(entry.data);entry=entry.next;}}}}/** * @param args */public static void main(String[] args) {// TODO Auto-generated method stubMyHashSet<String> set=new MyHashSet<String>();for(int i=0;i<100;i++){set.add(i+"");}for(int i=0;i<10;i++){set.remove(i+"");}System.out.println(set.size);set.print();}}
附录:
用链地址法处理冲突时的Hash表结构示意图如下:
相关博客:
[1].HashMap的实现原理:http://zhangshixi.iteye.com/blog/672697
[2].LinkedHashMap的实现原理: http://zhangshixi.iteye.com/blog/673789
4 0
- 重温数据结构:哈希表,MyHashMap与MyHashSet的Java实现
- myhashmap.java
- 重温数据结构-线性表的顺序表示与实现
- 重温数据结构:二叉查找树的java实现
- 重温数据结构:树 及 Java 实现
- 重温数据结构:树 及 Java 实现
- 重温数据结构:栈的顺序表示和实现与栈的链式表示和实现
- 重温数据结构:二叉树的常见方法及三种遍历方式 Java 实现
- 重温数据结构:二叉树的常见方法及三种遍历方式 Java 实现
- 【数据结构重温】哈希表
- 重温数据结构与算法(2) 编程中最常用,最通用的数据结构---数组和ArrayList
- 重温《C++ Primer》笔记七 VTABLE与VPTR的实现
- Java数据结构与算法---栈的实现
- 重温数据结构:队列的链式实现、顺序实现及循环队列
- 重温数据结构:单链表的常见问题总结
- 重温数据结构:二叉树的常见问题汇总
- 重温数据结构:Huffman树的建立
- 重温数据结构——图的遍历
- Chromium开源项目的代码统计
- cf404D Minesweeper 1D 状态转移dp
- dex relate files
- 导出excel功能,较通用的一种实现
- 黑马程序员 Java基础之IO流<一>File类及递归
- 重温数据结构:哈希表,MyHashMap与MyHashSet的Java实现
- UI 血条批次优化
- session 与 cookie
- AAM与ASM的区别
- NGUI--怎么控制Input中的输入的字符长度和类型
- PL/SQL触发器3(使用DML触发器)
- Android的七巧板Activity之二 Activity的加载模式
- 第五周项目1-三角形类的构造函数(2)
- GitHub超详细图文攻略 - Git客户端下载安装 GitHub提交修改源码工作流程 Git分支 标签 过滤 Git版本工作流