Last active
January 25, 2019 05:55
-
-
Save mohno007/1b9d8b0dbfb35c3bdf7a03e954ed0857 to your computer and use it in GitHub Desktop.
HashMap `javac hashmap.java && java -enableassertions hashmap`
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import java.lang.SuppressWarnings; | |
| import java.util.Optional; | |
| import java.util.Objects; | |
| class hashmap { | |
| static class HashMap<K, V> { | |
| private class Entry { | |
| public final K key; | |
| public V value; | |
| public Entry next = null; | |
| public Entry(K key, V value) { | |
| this.key = key; | |
| this.value = value; | |
| } | |
| } | |
| private Object[] bucket; | |
| private int length; | |
| public HashMap(int length) { | |
| assert(length > 0): "`length` must be grater than 0"; | |
| this.bucket = new Object[length]; | |
| this.length = length; | |
| } | |
| // キーに紐づく値を追加する | |
| void put(K key, V value) { | |
| Objects.requireNonNull(key, "`key` must not be null"); | |
| var hashCode = Math.abs(key.hashCode()); | |
| var newEntry = new Entry(key, value); | |
| // ハッシュ値を元に、配列を索引する | |
| @SuppressWarnings("unchecked") | |
| var foundEntry = (Entry)this.bucket[hashCode % this.length]; | |
| // エントリがなければ、最初のエントリなので、そのまま代入する | |
| if (foundEntry == null) { | |
| this.bucket[hashCode % this.length] = newEntry; | |
| return; | |
| // エントリがある場合は Entry#next をたどっていって、 | |
| // * Entry#nextがnullなら: Entry#nextに新しいEntryをくっつける | |
| // * Entry#key が一致するなら: 値を上書き | |
| } else { | |
| for (; foundEntry.next != null && !foundEntry.key.equals(key); foundEntry = foundEntry.next) {} | |
| if (foundEntry.key.equals(key)) { | |
| foundEntry.value = value; | |
| } else { | |
| foundEntry.next = newEntry; | |
| } | |
| } | |
| } | |
| // キーに紐づく値を取ってくる | |
| Optional<V> find(K key) { | |
| Objects.requireNonNull(key, "`key` must not be null"); | |
| var hashCode = Math.abs(key.hashCode()); | |
| @SuppressWarnings("unchecked") | |
| var foundEntry = (Entry)this.bucket[hashCode % this.length]; | |
| if (foundEntry == null) { | |
| return Optional.empty(); | |
| } | |
| for (; !foundEntry.key.equals(key) && foundEntry != null; foundEntry = foundEntry.next) {} | |
| return Optional | |
| .ofNullable(foundEntry) | |
| .map(entry -> entry.value); | |
| } | |
| } | |
| public static void main(String args[]) { | |
| var map = new HashMap<String, Integer>(10); | |
| // 名前と年齢をセットしてみる | |
| map.put("Yamada", 34); | |
| // 見つかるはず | |
| assert(map.find("Yamada").isPresent()); | |
| // 年齢は一致するはず | |
| assert(map.find("Yamada").get().equals(34)); | |
| // 入れてないキーに対応する値はあるはずがない | |
| assert(! map.find("Suzuki").isPresent()); | |
| // 他の名前と年齢もセットしてみる | |
| map.put("Watanabe", 20); | |
| assert(map.find("Watanabe").isPresent()); | |
| assert(map.find("Watanabe").get().equals(20)); | |
| // Suzukiさんを追加したら、あるはず。 | |
| map.put("Suzuki", 50); | |
| assert(map.find("Suzuki").isPresent()); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment