基于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采用的是冲突链表方式 从上图容易看出,如果选择 ...
随机推荐
- Eclipse:An error has occurred. See error log for more details. java.lang.NullPointerException
问题描述 在使用 Eclipse Clean 项目时报错:An error has occurred. See error log for more details. java.lang.Null ...
- 定时任务框架Quartz-(一)Quartz入门与Demo搭建
注:本文来源于:是Guava不是瓜娃 <定时任务框架Quartz-(一)Quartz入门与Demo搭建> 一.什么是Quartz 什么是Quartz? Quartz是OpenSympho ...
- SpringBoot整合Swagger测试api构建
@Author:SimpleWu 什么是Swagger? Swagger是什么:THE WORLD'S MOST POPULAR API TOOLING 根据官网的介绍: Swagger Inspec ...
- C++—模板(1)模板与函数模板
1.引入 如何编写一个通用加法函数?第一个方法是使用函数重载, 针对每个所需相同行为的不同类型重新实现这个函数.C++的这种编程机制给编程者极大的方便,不需要为功能相似.参数不同的函数选用不同的函数名 ...
- BFC知识点概括与总结
什么是BFC?如何生成一个BFC?BFC有什么作用? 一:什么是BFC? 首先了解CSS中两个概念:box和formatting context. Box:CSS布局中的基本单位.一个页面由多个box ...
- [原创]基于Zynq PS与PL之间寄存器映射 Standalone & Linux 例程
基于Zynq PS与PL之间寄存器映射 Standalone & Linux 例程 待添加完善中
- .net 获取配置文件AppSettings的键值
//AppSettings.config 节点代码 <appSettings> <add key="IsUpdate" value="false&quo ...
- UOJ#335. 【清华集训2017】生成树计数 多项式,FFT,下降幂,分治
原文链接www.cnblogs.com/zhouzhendong/p/UOJ335.html 前言 CLY大爷随手切这种题. 日常被CLY吊打系列. 题解 首先从 pruffer 编码的角度考虑这个问 ...
- Linux中的官方源、镜像源汇总
转载一篇文章,很有用 (一).企业站 搜狐: http://mirrors.sohu.com/ 网易: http://mirrors.163.com/ 阿里云: http://mirrors.aliy ...
- Python3-Cookbook总结 - 第二章:字符串和文本
第二章:字符串和文本 几乎所有有用的程序都会涉及到某些文本处理,不管是解析数据还是产生输出. 这一章将重点关注文本的操作处理,比如提取字符串,搜索,替换以及解析等. 大部分的问题都能简单的调用字符串的 ...