HashMap 자바 직접구현

서버란·2024년 9월 14일

CS 지식

목록 보기
4/25

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())
        );
    }


}
profile
백엔드에서 서버엔지니어가 된 사람

0개의 댓글