基于Java的HashMap和HashSet实现
一、Map接口类:
import java.util.Iterator; public interface IMap<K, V> {
/* 清除所有键值对 */
void clear(); /* key是否已经存在 */
boolean containsKey(K key); /* value是否存在 */
boolean containsValue(V value); /* 根据key获得value */
V get(K key); /* map是否为空 */
boolean isEmpty(); /* 所有key组成的数组 */
MyHashSet<K> keySet(); /* 存入键值对 */
void put(K key, V value); /* 把另外一个map中的所有键值对存入到当前map中 */
void putAll(IMap<? extends K, ? extends V> map); /* 根据key删除一个键值对 */
V remove(K key); /* 键值对的个数 */
int size(); /* 所有的value组成的数组 */
V[] values(); Iterator<MyHashMap.Node> iterator();
}
二、HashSet接口类:
import java.util.Iterator; public interface IHashSet<E> {
void add(E key); void remove(E key); void clear(); boolean contains(E key); boolean isEmpty(); int size(); Iterator<E> iterator();
}
三、HashMap类:
import java.util.Iterator; public class MyHashMap<K, V> implements IMap<K, V> {
private int length = 16; private Node[] buckets = new Node[length];// 桶
private int size; @Override
public void clear() {
for (int i = 0; i < buckets.length; i++) {
buckets[i] = null;
}
} @Override
public boolean containsKey(K key) {
int index = hash1(key);
if (buckets[index] == null) {
return false;
} else {
Node<K, V> p = buckets[index];// 相当于在链表中找key
while (p != null) {
K k1 = p.key;
// Java == 比较的是地址
// 借用java机制,hashcode和equals都来自于Object,用户可以改写这两个方法——制定对象相等的规则
if (k1 == key || (k1.hashCode() == key.hashCode() && k1.equals(key))) {
return true;
}
p = p.next;
}
} return false;
} @Override
public boolean containsValue(V value) {
for (int i = 0; i < buckets.length; i++) {
if (buckets[i] != null) {
Node<K, V> p = buckets[i];
while (p != null) {
if (p.value.equals(value))
return true;
}
}
}
return false;
} @Override
public V get(K key) {
int index = hash1(key);
if (buckets[index] == null) {
return null;
} else {
Node<K, V> p = buckets[index];
while (p != null) {
K k1 = p.key;
if (k1 == key || (k1.hashCode() == key.hashCode() && k1.equals(key))) {
return p.value;
}
p = p.next;
}
}
return null;
} @Override
public boolean isEmpty() {
return size == 0;
} @Override
public MyHashSet<K> keySet() {
MyHashSet<K> set = new MyHashSet<>();
for (int i = 0; i < buckets.length; i++) {
if (buckets[i] != null) {
Node<K, V> p = buckets[i];
while (p != null) {
set.add(p.key);
p = p.next;
}
}
}
return set;
} @Override
public void put(K key, V value) {
Node<K, V> node = new Node<>(key, value);
int index = hash1(key);// 算出在桶中的位置
if (buckets[index] == null) {// 桶中没有东西
buckets[index] = node;
size++;
} else {
Node<K, V> p = buckets[index];// 链表的表头找到
while (p != null) {
K k1 = p.key;
if (key == k1 || key.hashCode() == k1.hashCode() && key.equals(k1)) {
p.value = value;// 存在相同的key,则更新value
break;
}
if (p.next == null) {
p.next = node;
size++;
break;
}
p = p.next;
} }
} private int hash1(K key) {
// return key.hashCode() % length;
int h = 0;
int seed = 31;// 素数
String s = key.toString();
for (int i = 0; i != s.length(); ++i) {
h = seed * h + s.charAt(i);
}
return h % length;
} @Override
public void putAll(IMap<? extends K, ? extends V> map) { } @Override
public V remove(K key) {
int index = hash1(key);// 先定桶的位置
if (buckets[index] == null) {
return null;
} else {
Node<K, V> p = buckets[index];// 找到表头
Node<K, V> pre = p; while (p != null) {
K k1 = p.key;
if (k1.hashCode() == key.hashCode() && k1.equals(key)) {
// 移除
if (p == pre) {
buckets[index] = pre.next;
} else {
pre.next = p.next;
}
size--;
return p.value;
}
pre = p;
p = p.next;
}
}
return null;
} @Override
public int size() {
return size;
} @Override
public V[] values() {
return null;
} private class MapInterator implements Iterator<Node> {
int i = 0;
Node p = buckets[0]; @Override
public boolean hasNext() {
while (this.i < length && p == null) {
this.i++;
if (this.i == length)
p = null;
else
p = buckets[this.i];
}
// i是一个非空的桶,p是链表头
return p != null;
} @Override
public Node next() {
Node res = p;
p = p.next;
return res;
}
} @Override
public Iterator<Node> iterator() {
return new MapInterator();
} @Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < buckets.length; i++) {
if (buckets[i] != null) {
Node<K, V> p = buckets[i];
while (p != null) {
sb.append("(" + p.key + "," + p.value + "),");
p = p.next;
}
}
}
return sb.toString();
} public class Node<K, V> {
public K key;
public V value; public Node(K key, V value) {
this.key = key;
this.value = value;
} private Node next; @Override
public String toString() {
return "BSTNode{" + "key=" + key + ", value=" + value + '}';
}
}
}
四、HashSet类:
import java.util.Iterator; public class MyHashSet<E> implements IHashSet<E> {
private MyHashMap<E, E> map = new MyHashMap<>(); @Override
public void add(E key) {
map.put(key, null);
} @Override
public void remove(E key) {
map.remove(key);
} @Override
public void clear() {
map.clear();
} @Override
public boolean contains(E key) {
return map.containsKey(key);
} @Override
public boolean isEmpty() {
return map.isEmpty();
} @Override
public int size() {
return map.size();
} @Override
public Iterator<E> iterator() {
Iterator<MyHashMap.Node> iter = map.iterator();
return new Iterator<E>() {
@Override
public boolean hasNext() {
return iter.hasNext();
} @Override
public E next() {
return (E) iter.next().key;
}
};
} @Override
public String toString() {
Iterator<MyHashMap.Node> iterator = map.iterator();
StringBuilder sb = new StringBuilder();
while (iterator.hasNext()) {
sb.append(iterator.next().key + ",");
}
return sb.toString();
}
}
五、HashMap优化:
1、扩容:如果当表中的75%已经被占用,即视为需要扩容了。
2、如果冲突造成的链表长度超过8的时候,就要转为红黑树存储。
3、hash函数优化。h = key.hashCode(); h^(h>>16); h % length。
基于Java的HashMap和HashSet实现的更多相关文章
- 【转】Java学习---HashMap和HashSet的内部工作机制
[原文]https://www.toutiao.com/i6593863882484220430/ HashMap和HashSet的内部工作机制 HashMap 和 HashSet 内部是如何工作的? ...
- [Java语言] HashMap,HashSet,Hashtable,Vector,ArrayList 的关系 <转>
这么几个比较常用的但是比较容易混淆的概念同出于 java.util 包.本文仅作几个类的浅度解析. (本文基于JDK1.7,源码来自openjdk1.7.) ├── Collection │ ├── ...
- 刷题upupup【Java中HashMap、HashSet用法总结】
HashMap: 常用操作 1. containsKey() 判断HashMap是否包含key 2. containsValue() 判断HashMap是否包含“值为value”的元素 3. get( ...
- java遍历hashMap、hashSet、Hashtable
一.遍历HashMap Map<Integer, String> map = new HashMap<Integer, String>(); 方法一:效率高 for(Entry ...
- Java set接口之HashSet集合原理讲解
Set接口 java.util.set接口继承自Collection接口,它与Collection接口中的方法基本一致, 并没有对 Collection接口进行功能上的扩充,只是比collection ...
- java该HashTable,HashMap和HashSet
同一时候我们也对HashSet和HashMap的核心方法hashcode进行了具体解释,见<探索equals()和hashCode()方法>. 万事俱备,那么以下我们就对基于hash算法的 ...
- java集合HashMap、HashTable、HashSet详解
一.Set和Map关系 Set代表集合元素无序,集合元素不可重复的集合,Map代表一种由多个key-value组成的集合,map集合是set集合的扩展只是名称不同,对应如下 二.HashMap的工作原 ...
- Java笔记(七)HashMap和HashSet
HashMap和HashSet 一)HashMap 1.Map接口 interface Map<K,V> { int size();//查看Map中的键值对个数 boolean isEmp ...
- Java 集合 HashMap & HashSet 拾遗
Java 集合 HashMap & HashSet 拾遗 @author ixenos 摘要:HashMap内部结构分析 Java HashMap采用的是冲突链表方式 从上图容易看出,如果选择 ...
随机推荐
- VIM 编辑器
可视化模块 进入vi/vim编辑器,按CTRL+V进入可视化模式(VISUAL BLOCK) 2 移动光标上移或者下移,选中多行的开头,如下图所示 3 选择完毕后,按大写的的I键,此时下方会提示进入“ ...
- python Django2.X,报错 ‘learning_logs ’is not a registered namespace,如何解决?
自己也查阅了自己出现了的问题,其中就有这么个按照书中来写的代码但是Django却是提示了 ‘learning_logs ’is not a registered namespace. 然后错误提示可 ...
- cmake编译opencv时指定cuda版本
之前有网友提问说,基于cmake编译时如果切换cuda版本,比如我同时装了cuda8和cuda9,opencv总是找到cuda9,我想用cuda8怎么办?实际上,手头上要配置的工程是基于opencv3 ...
- [原创]Vivado SDK Initializing s/w repositories不动
21:56:16 INFO : Launching XSDB server: xsdb.bat C:/Xilinx/SDK/2015.4/scripts/xsdb/xsdb/xsdb-server.t ...
- MyBatis异常:元素内容必须由格式正确的字符数据或标记组成
今天在写接口查询SQL时,报了一个异常,如下: Cause: org.apache.ibatis.builder.BuilderException: Error creating document i ...
- JMeter关联的几种方式总结案例
1.接口响应结果,通常为HTML.JSON格式的数据,对于HTML的响应结果的提取,可以通过正则表达式,也可以通过XPath 来提取. 2.对于JSON格式的数据,可以通过正则表达式.JSON Ext ...
- flink连接hbase方法及遇到的问题
1.继承 RichSinkFunction 类 mvn配置: <dependency> <groupId>org.apache.flink</groupId> &l ...
- 微信小程序视频学习笔记
[清华大学]学做小程序 https://www.bilibili.com/video/av21987398 2.2创建项目和文件结构 小程序包含一个描述整体程序的app和多个描述各自页面的page 配 ...
- CF498C. Array and Operations [二分图]
CF498C. Array and Operations 题意: 给定一个长为 n 的数组,以及 m 对下标 (a, b) 且满足 a + b 为奇数,每次操作可以将同一组的两个数同时除以一个公约数 ...
- 关于最小生成树,拓扑排序、强连通分量、割点、2-SAT的一点笔记
关于最小生成树,拓扑排序.强连通分量.割点.2-SAT的一点笔记 前言:近期在复习这些东西,就xjb写一点吧.当然以前也写过,但这次偏重不太一样 MST 最小瓶颈路:u到v最大权值最小的路径.在最小生 ...