Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 

README.md

05. 해시맵 (HashMap)

📋 문제 정의

해시 함수를 사용하여 키-값 쌍을 저장하는 **해시맵(HashMap)**을 구현하세요.

평균 O(1) 시간에 삽입, 삭제, 검색이 가능한 핵심 자료구조입니다.


🎯 학습 목표

  • 해시 함수의 원리 이해
  • 해시 충돌(Collision) 해결 방법
  • 체이닝(Chaining) vs 개방 주소법(Open Addressing)
  • 로드 팩터(Load Factor)와 리해싱(Rehashing)
  • equals()와 hashCode() 계약 이해

📝 요구사항

기본 연산

메서드 설명 평균 시간복잡도
put(key, value) 키-값 쌍 저장 (키 있으면 덮어쓰기) O(1)
get(key) 키에 해당하는 값 반환 O(1)
remove(key) 키-값 쌍 삭제 O(1)
containsKey(key) 키 존재 여부 확인 O(1)
containsValue(value) 값 존재 여부 확인 O(n)
size() 저장된 키-값 쌍 개수 O(1)
isEmpty() 비어있는지 확인 O(1)
clear() 모든 요소 삭제 O(n)
keySet() 모든 키 집합 반환 O(n)
values() 모든 값 컬렉션 반환 O(n)
entrySet() 모든 키-값 쌍 집합 반환 O(n)

충돌 해결 방식

  1. 체이닝 (Separate Chaining)

    • 각 버킷에 연결 리스트 저장
    • Java 8+에서는 트리화 (8개 이상 → Red-Black Tree)
  2. 개방 주소법 (Open Addressing)

    • 선형 탐사 (Linear Probing)
    • 이차 탐사 (Quadratic Probing)
    • 이중 해싱 (Double Hashing)

📊 입출력 예시

예제 1: 기본 사용

HashMap<String, Integer> map = new HashMap<>();
map.put("apple", 100);
map.put("banana", 200);
map.put("cherry", 300);

System.out.println(map.get("apple"));     // 출력: 100
System.out.println(map.get("grape"));     // 출력: null
System.out.println(map.containsKey("banana")); // 출력: true

예제 2: 값 덮어쓰기

HashMap<String, Integer> map = new HashMap<>();
map.put("key", 1);
map.put("key", 2);  // 기존 값 덮어쓰기

System.out.println(map.get("key"));  // 출력: 2
System.out.println(map.size());      // 출력: 1

예제 3: 삭제

HashMap<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);

Integer removed = map.remove("a");
System.out.println(removed);              // 출력: 1
System.out.println(map.containsKey("a")); // 출력: false

예제 4: null 키/값

HashMap<String, Integer> map = new HashMap<>();
map.put(null, 100);      // null 키 허용
map.put("key", null);    // null 값 허용

System.out.println(map.get(null));   // 출력: 100
System.out.println(map.get("key"));  // 출력: null

🔍 제약 조건

  • 초기 용량: 16 (2의 거듭제곱)
  • 로드 팩터: 0.75 (75% 차면 리해싱)
  • 리해싱: 용량 2배로 확장
  • null 키/값 허용 (구현 방식에 따라)
  • equals()와 hashCode() 일관성 필요

💡 힌트

해시 함수

// 버킷 인덱스 계산
int hash = key.hashCode();
int index = hash & (capacity - 1);  // capacity가 2의 거듭제곱일 때

// 또는
int index = Math.abs(hash) % capacity;

체이닝 구현 힌트

class Entry<K, V> {
    K key;
    V value;
    Entry<K, V> next;  // 연결 리스트
}

Entry<K, V>[] buckets = new Entry[capacity];

개방 주소법 힌트

// 선형 탐사
int index = hash & (capacity - 1);
while (buckets[index] != null && !buckets[index].key.equals(key)) {
    index = (index + 1) & (capacity - 1);
}

✅ 체크리스트

  • 체이닝 방식 해시맵 구현
  • 개방 주소법(선형 탐사) 해시맵 구현
  • 로드 팩터 기반 리해싱
  • null 키/값 처리
  • equals/hashCode 올바른 사용
  • keySet, values, entrySet 구현
  • Iterator 구현

📚 참고