【数据结构和算法】——|【数据结构和算法】—— 哈希表

1.什么是哈希表 哈希表是结合哈希算法结合其他数据结构构成的一种数据结构。
为什么会产生这样的数据结构呢?
主要原因是在理想情况下,取出和放入元素所消耗的时间复杂度为
\( O(1) \)
【【数据结构和算法】——|【数据结构和算法】—— 哈希表】比如我们看一种常见的实现方式,哈希算法+数组+链表构成的哈希表:
假设数组index从1开始,那么根据哈希算法,元素1就放在数组下标为1的地方,元素3就放在数组下标为3的地方,元素5放在数组下标为1的地方,但是因为元素1已经在数组中了,对于这种情况,我们的一种解决方式就是元素1和元素5通过链表连接,元素1仍然在数组中,新加入的元素5放在元素1后面,元素1的next节点指向元素5.
【数据结构和算法】——|【数据结构和算法】—— 哈希表
文章图片

2. java实现 哈希表的用途很广,比如java的HashMap、HashSet。
对于哈希表,我们的操作主要是PUT和GET操作。
下面就来看看怎么实现简易版本的HashMap。

import java.util.Arrays; import java.util.Objects; /** * key and value are not permitted null * @author bennetty74 * @since 2021.10.24 */ public class HashMap implements Map{ // 声明一个ENTRY数组用于存放元素 private Entry[] entries; private final double loadFactor = 0.75d; private int capacity = 8; private int size = 0; @SuppressWarnings("unchecked") public HashMap() { entries = new Entry[this.capacity]; }@SuppressWarnings("unchecked") public HashMap(int capacity) { this.capacity = capacity; entries = new Entry[capacity]; }@Override public boolean contains(K key) { int idx = getIndex(key); if (entries[idx] == null) { return false; } Entry entry = entries[idx]; while (entry != null) { if (entry.key.equals(key)) { return true; } entry = entry.next; } return false; } // put操作,不允许key和value为null public boolean put(K key, V value) { if (Objects.isNull(key) || Objects.isNull(value)) { throw new IllegalArgumentException("Key or value is null"); } int idx = getIndex(key); // if null, put in entries array if (Objects.isNull(entries[idx])) { entries[idx] = new Entry<>(key, value); } else { // else put at the head of Entry list Entry newEntry = new Entry<>(key, value); newEntry.next = entries[idx]; entries[idx] = newEntry; } // if load factor greater than 0.75, then rehash if (size++ / (double) capacity > 0.75f) { rehash(); } return true; }private void rehash() { capacity = 2 * capacity; Entry[] oldEntries = Arrays.copyOf(this.entries, capacity); entries = new Entry[capacity]; for (Entry oldEntry : oldEntries) { if (oldEntry != null) { put(oldEntry.key, oldEntry.value); } } }public V get(K key) { if (Objects.isNull(key)) { throw new IllegalArgumentException("Key is null"); } // get idx by key's hashCode int idx = getIndex(key); Entry entry = entries[idx]; if (!Objects.isNull(entry)) { while (!Objects.isNull(entry)) { if (key.equals(entry.key)) { return entry.value; } entry = entry.next; } } // not found the specific key, return null return null; } // 此处的hash算法很简单,就是根据key的hashCode除以entry数组的容量的余数作为数组下标存放元素 private int getIndex(K key) { return key.hashCode() % capacity; }@Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("HashMap { "); for (int i = 0; i < capacity; i++) { if (entries[i] != null) { Entry entry = entries[i]; while (entry != null) { sb.append(entry.key).append("=").append(entry.value).append(","); entry = entry.next; } } } sb.replace(sb.length() - 1, sb.length(), "").append(" }"); return sb.toString(); }// Entry类,包含HashMap的key和value private static class Entry { K key; V value; public Entry(K key, V value) { this.key = key; this.value = https://www.it610.com/article/value; }Entry next; }}

    推荐阅读