IMap 인터페이스
public interface IMap<K, V> {
void clear();
boolean containsKey(K key);
boolean containsValue(V value);
V get(K key);
boolean isEmpty();
V put(K key, V value);
void remove(K key);
int size();
}
HashNode 클래스
public class HashNode<K,V> {
private final int hash;
private final K key;
private V value;
private HashNode<K,V> next;
public HashNode(int hash, K key, V value) {
this.hash = hash;
this.key = key;
this.value = value;
}
public int getHash() {
return hash;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
public HashNode getNext() {
return next;
}
public void setNext(HashNode next) {
this.next = next;
}
}
MyHashMap클래스
import com.nhnacademy.hashmap.IMap;
import com.nhnacademy.hashmap.node.HashNode;
import java.util.*;
public class MyHashMap<K, V> implements IMap<K, V> {
//Todo 1. HashNode를 이용하여 구현합니다.
private static final int DEFAULT_CAPACITY = 31;
private int size;
private HashNode<K, V>[] table;
private int hash(K key) {
if (key == null) {
throw new IllegalArgumentException();
}
// System.out.println(Objects.hashCode(key) % 31);
return Objects.hashCode(key) % 31;
}
public MyHashMap() {
table = new HashNode[DEFAULT_CAPACITY];
size = 0;
}
@Override
public void clear() {
table = new HashNode[DEFAULT_CAPACITY];
size = 0;
// if (table != null) {
// System.out.println("null table");
// }
}
@Override
public boolean containsKey(K key) {
int index = hash(key);
HashNode<K, V> node = table[index];
while (node != null) {
if (Objects.equals(node.getKey(), key)) {
return true;
}
node = node.getNext();
}
return false;
}
@Override
public boolean containsValue(V value) {
for (HashNode<K, V> node : table) {
while (node != null) {
if (Objects.equals(node.getValue(), value)) {
return true;
}
node = node.getNext();
}
}
return false;
}
@Override
public V get(K key) {
if(!containsKey(key)) {
throw new IllegalArgumentException();
}
int index = hash(key);
HashNode<K, V> node = table[index];
while (node != null) {
if (Objects.equals(node.getKey(), key)) {
return node.getValue();
}
node = node.getNext();
}
return null;
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public V put(K key, V value) {
int index = hash(key);
HashNode<K, V> node = table[index];
while (node != null) {
if (Objects.equals(node.getKey(), key)) {
V oldValue = node.getValue();
node.setValue(value);
return oldValue;
}
node = node.getNext();
}
HashNode<K, V> newNode = new HashNode<>(index, key, value);
newNode.setNext(table[index]);
table[index] = newNode;
size++;
return newNode.getValue();
}
@Override
public void remove(K key) {
int index = hash(key);
HashNode<K, V> node = table[index];
HashNode<K, V> prev = null;
while (node != null) {
if (Objects.equals(node.getKey(), key)) {
if (prev == null) {
table[index] = node.getNext();
} else {
prev.setNext(node.getNext());
}
size--;
return;
}
prev = node;
node = node.getNext();
}
}
@Override
public int size() {
return size;
}
}
MyHashMapTest
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
class MyHashMapTest {
//Todo 2. 구현한 MyHashMap을 적절히 테스트합니다.
MyHashMap<Integer, Integer> myHashMap;
@BeforeEach
@DisplayName("해쉬맵 생성, 6개 노드 put")
void setUp() {
myHashMap = new MyHashMap<>();
// 현재 인덱스위치
myHashMap.put(0, 100); // 0
myHashMap.put(1, 101); // 1
myHashMap.put(2, 102); // 2
myHashMap.put(3, 103); // 3
myHashMap.put(31, 1031); // 0
myHashMap.put(32, 1032); // 1
}
@Test
@DisplayName("키가 존재하는지")
void containsKey() {
Assertions.assertAll(
() -> Assertions.assertTrue(myHashMap.containsKey(0)),
() -> Assertions.assertFalse(myHashMap.containsKey(5))
);
}
@Test
@DisplayName("값이 존재하는지")
void containsValue() {
Assertions.assertAll(
() -> Assertions.assertTrue(myHashMap.containsValue(1031)),
() -> Assertions.assertFalse(myHashMap.containsValue(104))
);
}
@Test
@DisplayName("키가 있으면 그 값 가져오기")
void get1() {
Assertions.assertEquals(100, myHashMap.get(0));
}
@Test
@DisplayName("키가 없으면 예외처리")
void get2() {
Assertions.assertThrows(IllegalArgumentException.class, () -> myHashMap.get(5));
}
@Test
@DisplayName("현재 비어있는가 false")
void isEmpty() {
Assertions.assertFalse(myHashMap.isEmpty());
}
@Test
@DisplayName("키와 값이 잘 들어갔는가")
void put() {
myHashMap.put(777,777);
Assertions.assertTrue(myHashMap.containsKey(777));
}
@Test
@DisplayName("키와 값이 잘 제거됬는가")
void remove() {
myHashMap.remove(32);
Assertions.assertFalse(myHashMap.containsKey(32));
}
@Test
void size() {
Assertions.assertEquals(myHashMap.size(), 6);
}
@Test
@DisplayName("size = 0, myHashMap이 비어있어야 된다")
void clear() {
myHashMap.clear();
Assertions.assertAll(
() -> Assertions.assertEquals(myHashMap.size(), 0),
() -> Assertions.assertEquals(true, myHashMap.isEmpty())
);
}
}