基于Java的HashMap和HashSet实现
一、Map接口类:

1 import java.util.Iterator; 2 3 public interface IMap<K, V> { 4 /* 清除所有键值对 */ 5 void clear(); 6 7 /* key是否已经存在 */ 8 boolean containsKey(K key); 9 10 /* value是否存在 */ 11 boolean containsValue(V value); 12 13 /* 根据key获得value */ 14 V get(K key); 15 16 /* map是否为空 */ 17 boolean isEmpty(); 18 19 /* 所有key组成的数组 */ 20 MyHashSet<K> keySet(); 21 22 /* 存入键值对 */ 23 void put(K key, V value); 24 25 /* 把另外一个map中的所有键值对存入到当前map中 */ 26 void putAll(IMap<? extends K, ? extends V> map); 27 28 /* 根据key删除一个键值对 */ 29 V remove(K key); 30 31 /* 键值对的个数 */ 32 int size(); 33 34 /* 所有的value组成的数组 */ 35 V[] values(); 36 37 Iterator<MyHashMap.Node> iterator(); 38 }
二、HashSet接口类:

1 import java.util.Iterator; 2 3 public interface IHashSet<E> { 4 void add(E key); 5 6 void remove(E key); 7 8 void clear(); 9 10 boolean contains(E key); 11 12 boolean isEmpty(); 13 14 int size(); 15 16 Iterator<E> iterator(); 17 }
三、HashMap类:

1 import java.util.Iterator; 2 3 public class MyHashMap<K, V> implements IMap<K, V> { 4 private int length = 16; 5 6 private Node[] buckets = new Node[length];// 桶 7 private int size; 8 9 @Override 10 public void clear() { 11 for (int i = 0; i < buckets.length; i++) { 12 buckets[i] = null; 13 } 14 } 15 16 @Override 17 public boolean containsKey(K key) { 18 int index = hash1(key); 19 if (buckets[index] == null) { 20 return false; 21 } else { 22 Node<K, V> p = buckets[index];// 相当于在链表中找key 23 while (p != null) { 24 K k1 = p.key; 25 // Java == 比较的是地址 26 // 借用java机制,hashcode和equals都来自于Object,用户可以改写这两个方法——制定对象相等的规则 27 if (k1 == key || (k1.hashCode() == key.hashCode() && k1.equals(key))) { 28 return true; 29 } 30 p = p.next; 31 } 32 } 33 34 return false; 35 } 36 37 @Override 38 public boolean containsValue(V value) { 39 for (int i = 0; i < buckets.length; i++) { 40 if (buckets[i] != null) { 41 Node<K, V> p = buckets[i]; 42 while (p != null) { 43 if (p.value.equals(value)) 44 return true; 45 } 46 } 47 } 48 return false; 49 } 50 51 @Override 52 public V get(K key) { 53 int index = hash1(key); 54 if (buckets[index] == null) { 55 return null; 56 } else { 57 Node<K, V> p = buckets[index]; 58 while (p != null) { 59 K k1 = p.key; 60 if (k1 == key || (k1.hashCode() == key.hashCode() && k1.equals(key))) { 61 return p.value; 62 } 63 p = p.next; 64 } 65 } 66 return null; 67 } 68 69 @Override 70 public boolean isEmpty() { 71 return size == 0; 72 } 73 74 @Override 75 public MyHashSet<K> keySet() { 76 MyHashSet<K> set = new MyHashSet<>(); 77 for (int i = 0; i < buckets.length; i++) { 78 if (buckets[i] != null) { 79 Node<K, V> p = buckets[i]; 80 while (p != null) { 81 set.add(p.key); 82 p = p.next; 83 } 84 } 85 } 86 return set; 87 } 88 89 @Override 90 public void put(K key, V value) { 91 Node<K, V> node = new Node<>(key, value); 92 int index = hash1(key);// 算出在桶中的位置 93 if (buckets[index] == null) {// 桶中没有东西 94 buckets[index] = node; 95 size++; 96 } else { 97 Node<K, V> p = buckets[index];// 链表的表头找到 98 while (p != null) { 99 K k1 = p.key; 100 if (key == k1 || key.hashCode() == k1.hashCode() && key.equals(k1)) { 101 p.value = value;// 存在相同的key,则更新value 102 break; 103 } 104 if (p.next == null) { 105 p.next = node; 106 size++; 107 break; 108 } 109 p = p.next; 110 } 111 112 } 113 } 114 115 private int hash1(K key) { 116 // return key.hashCode() % length; 117 int h = 0; 118 int seed = 31;// 素数 119 String s = key.toString(); 120 for (int i = 0; i != s.length(); ++i) { 121 h = seed * h + s.charAt(i); 122 } 123 return h % length; 124 } 125 126 @Override 127 public void putAll(IMap<? extends K, ? extends V> map) { 128 129 } 130 131 @Override 132 public V remove(K key) { 133 int index = hash1(key);// 先定桶的位置 134 if (buckets[index] == null) { 135 return null; 136 } else { 137 Node<K, V> p = buckets[index];// 找到表头 138 Node<K, V> pre = p; 139 140 while (p != null) { 141 K k1 = p.key; 142 if (k1.hashCode() == key.hashCode() && k1.equals(key)) { 143 // 移除 144 if (p == pre) { 145 buckets[index] = pre.next; 146 } else { 147 pre.next = p.next; 148 } 149 size--; 150 return p.value; 151 } 152 pre = p; 153 p = p.next; 154 } 155 } 156 return null; 157 } 158 159 @Override 160 public int size() { 161 return size; 162 } 163 164 @Override 165 public V[] values() { 166 return null; 167 } 168 169 private class MapInterator implements Iterator<Node> { 170 int i = 0; 171 Node p = buckets[0]; 172 173 @Override 174 public boolean hasNext() { 175 while (this.i < length && p == null) { 176 this.i++; 177 if (this.i == length) 178 p = null; 179 else 180 p = buckets[this.i]; 181 } 182 // i是一个非空的桶,p是链表头 183 return p != null; 184 } 185 186 @Override 187 public Node next() { 188 Node res = p; 189 p = p.next; 190 return res; 191 } 192 } 193 194 @Override 195 public Iterator<Node> iterator() { 196 return new MapInterator(); 197 } 198 199 @Override 200 public String toString() { 201 StringBuilder sb = new StringBuilder(); 202 for (int i = 0; i < buckets.length; i++) { 203 if (buckets[i] != null) { 204 Node<K, V> p = buckets[i]; 205 while (p != null) { 206 sb.append("(" + p.key + "," + p.value + "),"); 207 p = p.next; 208 } 209 } 210 } 211 return sb.toString(); 212 } 213 214 public class Node<K, V> { 215 public K key; 216 public V value; 217 218 public Node(K key, V value) { 219 this.key = key; 220 this.value = value; 221 } 222 223 private Node next; 224 225 @Override 226 public String toString() { 227 return "BSTNode{" + "key=" + key + ", value=" + value + '}'; 228 } 229 } 230 }
四、HashSet类:

1 import java.util.Iterator; 2 3 public class MyHashSet<E> implements IHashSet<E> { 4 private MyHashMap<E, E> map = new MyHashMap<>(); 5 6 @Override 7 public void add(E key) { 8 map.put(key, null); 9 } 10 11 @Override 12 public void remove(E key) { 13 map.remove(key); 14 } 15 16 @Override 17 public void clear() { 18 map.clear(); 19 } 20 21 @Override 22 public boolean contains(E key) { 23 return map.containsKey(key); 24 } 25 26 @Override 27 public boolean isEmpty() { 28 return map.isEmpty(); 29 } 30 31 @Override 32 public int size() { 33 return map.size(); 34 } 35 36 @Override 37 public Iterator<E> iterator() { 38 Iterator<MyHashMap.Node> iter = map.iterator(); 39 return new Iterator<E>() { 40 @Override 41 public boolean hasNext() { 42 return iter.hasNext(); 43 } 44 45 @Override 46 public E next() { 47 return (E) iter.next().key; 48 } 49 }; 50 } 51 52 @Override 53 public String toString() { 54 Iterator<MyHashMap.Node> iterator = map.iterator(); 55 StringBuilder sb = new StringBuilder(); 56 while (iterator.hasNext()) { 57 sb.append(iterator.next().key + ","); 58 } 59 return sb.toString(); 60 } 61 }
五、HashMap优化:
1、扩容:如果当表中的75%已经被占用,即视为需要扩容了。
2、如果冲突造成的链表长度超过8的时候,就要转为红黑树存储。
3、hash函数优化。h = key.hashCode(); h^(h>>16); h % length。
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
本文来自博客园,作者:|旧市拾荒|,转载请注明原文链接:https://www.cnblogs.com/xiaoyh/p/10389610.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~