对比

对比 数组和链表组成的hash实现1 , 新增一次rehash的实现,提升性能处理。

实现

🚀🚀🚀 点我查看完整代码

  1. package io.github.chenshun00.data.hash;
  2. import java.util.Objects;
  3. /**
  4. * 相对复杂一点的hash实现,添加过程存在<em>rehash</em>的动作
  5. *
  6. * @author chenshun00@gmail.com
  7. * @since 2021/9/4 4:49 下午
  8. */
  9. public class ReHashImpl<K, V> implements Hash<K, V> {
  10. public Node<K, V>[] tables;
  11. private int capacity;
  12. private int size;
  13. int threshold;
  14. /**
  15. * 扩容因子
  16. *
  17. * @see java.util.HashMap#DEFAULT_LOAD_FACTOR
  18. */
  19. private final float factor;
  20. @SuppressWarnings("unchecked")
  21. public ReHashImpl(int capacity) {
  22. if (capacity <= 0) {
  23. throw new IllegalArgumentException("invalid capacity");
  24. }
  25. this.capacity = capacity;
  26. this.tables = new Node[capacity];
  27. factor = 0.75f;
  28. threshold = (int) (this.capacity * factor);
  29. }
  30. @Override
  31. public V put(K key, V value) {
  32. check(key, value);
  33. final int hash = hash(key);
  34. final int index = hash & (tables.length - 1);
  35. Node<K, V> head = tables[index];
  36. if (head == null) {
  37. final Node<K, V> kvNode = new Node<>(hash, key, value, null);
  38. tables[index] = kvNode;
  39. } else {
  40. if (head.k.equals(key)) {
  41. final V v = head.v;
  42. head.v = value;
  43. return v;
  44. }
  45. while (head.next != null) {
  46. head = head.next;
  47. final K k = head.k;
  48. if (k.equals(key)) {
  49. final V v = head.v;
  50. head.v = value;
  51. return v;
  52. }
  53. }
  54. head.next = new Node<>(hash, key, value, null);
  55. }
  56. incr();
  57. resize();
  58. return null;
  59. }
  60. @Override
  61. public V get(K key) {
  62. Objects.requireNonNull(key, "key can't be null");
  63. final int hash = hash(key);
  64. final int index = hash & (tables.length - 1);
  65. Node<K, V> head = tables[index];
  66. if (head == null) {
  67. return null;
  68. }
  69. if (head.k.equals(key)) {
  70. return head.v;
  71. }
  72. head = head.next;
  73. do {
  74. if (head.k.equals(key)) {
  75. return head.v;
  76. }
  77. head = head.next;
  78. } while (head.next != null);
  79. return null;
  80. }
  81. @Override
  82. public V remove(K key) {
  83. Objects.requireNonNull(key, "key can't be null");
  84. final int hash = hash(key);
  85. final int index = hash & (tables.length - 1);
  86. Node<K, V> head = tables[index];
  87. if (head == null) {
  88. return null;
  89. }
  90. if (head.k.equals(key)) {
  91. if (head.next == null) {
  92. tables[index] = null;
  93. } else {
  94. tables[index] = head.next;
  95. }
  96. decr();
  97. return head.v;
  98. }
  99. Node<K, V> leader = head;
  100. head = head.next;
  101. do {
  102. if (head.k.equals(key)) {
  103. leader.next = head.next;
  104. decr();
  105. return head.v;
  106. }
  107. leader = head;
  108. head = head.next;
  109. } while (head.next != null);
  110. return null;
  111. }
  112. @Override
  113. public int size() {
  114. return size;
  115. }
  116. @SuppressWarnings("unchecked")
  117. protected void resize() {
  118. if (shouldReHash()) {
  119. int oldCap = capacity;
  120. capacity = capacity << 1;
  121. final Node<K, V>[] newTables = new Node[capacity];
  122. for (int i = 0; i < tables.length; i++) {
  123. Node<K, V> headNode = tables[i];
  124. if (headNode != null) {
  125. //确定在新table中的下标索引
  126. Node<K, V> loHead = null, loTail = null;
  127. Node<K, V> hiHead = null, hiTail = null;
  128. Node<K, V> next;
  129. do {
  130. next = headNode.next;
  131. if ((headNode.hash & oldCap) == 0) {
  132. if (loTail == null)
  133. loHead = headNode;
  134. else
  135. loTail.next = headNode;
  136. loTail = headNode;
  137. } else {
  138. if (hiTail == null)
  139. hiHead = headNode;
  140. else
  141. hiTail.next = headNode;
  142. hiTail = headNode;
  143. }
  144. } while ((headNode = next) != null);
  145. if (loTail != null) {
  146. loTail.next = null;
  147. newTables[i] = loHead;
  148. }
  149. if (hiTail != null) {
  150. hiTail.next = null;
  151. newTables[i + oldCap] = hiHead;
  152. }
  153. }
  154. }
  155. tables = newTables;
  156. threshold = (int) (this.capacity * factor);
  157. }
  158. }
  159. private boolean shouldReHash() {
  160. return size >= threshold && tables.length <= 1024;
  161. }
  162. private void incr() {
  163. size++;
  164. }
  165. private void decr() {
  166. size--;
  167. }
  168. }

测试代码

  1. package io.github.chenshun00.data.hash;
  2. import org.junit.Assert;
  3. import org.junit.Test;
  4. /**
  5. * @author chenshun00@gmail.com
  6. * @since 2021/9/4 8:35 下午
  7. */
  8. public class ReHashImplTest {
  9. private final Hash<String, String> hash = new ReHashImpl<>(8);
  10. @Test
  11. public void put() {
  12. String key = "chenshun00";
  13. final String put = hash.put(key, "first");
  14. Assert.assertNull(put);
  15. final String result = hash.get(key);
  16. Assert.assertNotNull(result);
  17. Assert.assertEquals("first", result);
  18. Assert.assertEquals(1, hash.size());
  19. for (int i = 0; i < 10; i++) {
  20. Assert.assertNull(hash.put("chenshun00" + i, "chenshun00" + i));
  21. }
  22. Assert.assertEquals(11, hash.size());
  23. }
  24. @Test
  25. public void more() {
  26. String key = "chenshun00";
  27. final String put = hash.put(key, "first");
  28. Assert.assertNull(put);
  29. final String result = hash.get(key);
  30. Assert.assertNotNull(result);
  31. Assert.assertEquals("first", result);
  32. Assert.assertEquals(1, hash.size());
  33. for (int i = 0; i < 1000000; i++) {
  34. Assert.assertNull(hash.put("chenshun00" + i, "chenshun00" + i));
  35. }
  36. Assert.assertEquals(1000001, hash.size());
  37. }
  38. }