Menu
Coddy logo textTech

Hash Map

마지막 업데이트

해시 맵은 키-값 쌍을 저장하고 키로 값을 평균 O(1)에 조회할 수 있게 해줍니다. 해시 테이블과 완전히 같은 방식으로 동작하지만, 각 버킷 항목이 키와 그에 연결된 값을 모두 담습니다. 쌍을 저장하거나 가져오려면 키를 버킷 인덱스로 해싱한 다음, 그 버킷의 체인을 순회하며 일치하는 키를 찾습니다. 위의 재생 버튼을 눌러 쌍이 해시된 버킷에 배치되고 값이 키로 조회되는 과정을 확인하세요.

이것은 Python의 dict, Java의 HashMap, JavaScript의 Map/객체 뒤에 있는 구조입니다. 충돌은 해시 테이블과 동일하게 처리되며, 여기서는 분리 연결법으로 다룹니다. 따라서 성능은 좋은 해시 함수와 낮은 적재율에 달려 있습니다.

시간 복잡도

연산평균최악의 경우
삽입/갱신 (put)O(1)O(n)
조회 (get)O(1)O(n)
삭제O(1)O(n)
공간O(n)O(n)

주요 언어의 해시 맵

언어타입
Pythondict
JavaHashMap
JavaScriptMap / 객체
C++std::unordered_map
Gomap

예제 풀이

hash(key) % 8을 사용하여 쌍 ("cat", 3), ("dog", 5), ("cat", 9), ("emu", 7)을 버킷 8개짜리 맵에 삽입합니다. hash("cat") % 8 = 2, hash("dog") % 8 = 5, hash("emu") % 8 = 2라고 가정합니다:

단계구조동작
Put ("cat", 3)버킷 2: [("cat", 3)]버킷 2로 해싱; 체인이 비어 있으므로 쌍을 추가.
Put ("dog", 5)버킷 2: [("cat", 3)], 버킷 5: [("dog", 5)]버킷 5로 해싱; 체인이 비어 있으므로 쌍을 추가.
Put ("cat", 9)버킷 2: [("cat", 9)], 버킷 5: [("dog", 5)]버킷 2로 해싱; 키 "cat"이 이미 체인에 있으므로 값을 9로 갱신.
Put ("emu", 7)버킷 2: [("cat", 9), ("emu", 7)], 버킷 5: [("dog", 5)]버킷 2로 해싱; "cat"과 충돌하지만 키를 찾지 못하므로 쌍을 추가.
Get "emu"버킷 2: [("cat", 9), ("emu", 7)]버킷 2로 해싱; 체인을 순회하며 "cat"을 건너뛰고 "emu"와 일치, 7을 반환.

해시 맵을 사용해야 할 때

사용할 때피해야 할 때
정확한 키로 평균 O(1) 조회, 삽입, 삭제가 필요할 때.키를 정렬 순서로 유지하거나 범위 질의가 필요할 때 — 균형 BST나 정렬 맵을 사용.
키가 해시 가능하고 동등성이 잘 정의되어 있을 때(문자열, 정수, 튜플).키가 가변이고 삽입 후 바뀔 수 있을 때. 해당 버킷이 손상됨.
식별자로 세기, 중복 제거, 캐싱, 인덱싱을 할 때.상각 평균 한계가 아니라 최악의 경우 O(log n) 보장이 필요할 때.
순회 순서가 중요하지 않거나 삽입 순서 맵으로 충분할 때.메모리가 매우 빠듯할 때 — 버킷, 적재율 여유 공간, 포인터가 오버헤드를 더함.

Hash Map 코드

Python, JavaScript, Java, C++, C로 작성된 깔끔하고 실행 가능한 Hash Map 구현입니다. 언어를 선택해 코드를 복사하거나 Coddy 플레이그라운드에서 바로 열어보세요.

Python로 구현한 Hash Map 코드

Python
1# Python's built-in dict is a hash map: O(1) average2# insert, lookup, and delete.3inventory = {"apple": 3, "banana": 7}4
5# Insert and update6inventory["cherry"] = 57inventory["apple"] += 28
9# Lookup, with .get for a safe default on missing keys10print("apple: ", inventory["apple"])11print("mango: ", inventory.get("mango", 0))12
13# Membership test and delete14print("banana in stock:", "banana" in inventory)15del inventory["banana"]16print("banana in stock:", "banana" in inventory)17
18# Iterate over key-value pairs19for fruit, count in sorted(inventory.items()):20    print(f"{fruit}: {count}")21
22# Classic hash map use case: counting frequencies23words = "the quick brown fox jumps over the lazy dog the end".split()24freq = {}25for word in words:26    freq[word] = freq.get(word, 0) + 127
28print("Occurrences of the:", freq["the"])29print("Most common word:  ", max(freq, key=freq.get))
이 코드를 Python 플레이그라운드에서 실행하기

해시 맵 자주 묻는 질문

해시 맵과 해시 테이블의 차이는 무엇인가요?
본질적으로 같은 구조로, 키의 해시로 주소가 지정되는 버킷 배열입니다. 일반적인 용법에서 "해시 테이블"은 키의 집합이나 일반적인 기법을 가리키는 경우가 많고, "해시 맵"은 키-값 쌍의 저장을 강조합니다. 일부 언어는 스레드 안전성 구분도 둡니다(예: Java의 Hashtable와 HashMap)만, 핵심 알고리즘은 동일합니다.
해시 맵의 시간 복잡도는 어떻게 되나요?
put, get, delete는 좋은 해시 함수와 낮은 적재율에서 평균 O(1)입니다. 모든 키가 하나의 버킷으로 충돌하는 병적인 경우에는 O(n)으로 나빠지므로, 크기 조정과 좋은 해싱이 중요합니다.
해시 맵은 같은 버킷으로 해싱되는 두 키를 어떻게 처리하나요?
충돌을 해결합니다. 이 시각화는 분리 연결법을 사용합니다. 각 버킷은 작은 리스트를 담고, 키가 그곳으로 해싱되는 새 쌍은 그 리스트에 추가됩니다. 조회 시 맵은 짧은 체인을 순회하며 일치하는 키를 찾습니다. 대안 기법은 개방 주소법으로, 배열에서 다른 슬롯을 탐사합니다.
해시 맵과 이진 탐색 트리 중 무엇을 사용해야 하나요?
정확한 키로의 조회만 필요하고 평균 O(1) 연산을 원한다면 해시 맵을 사용하세요. 정렬된 키, 범위 질의, 선행자/후행자 조회가 필요하면 균형 이진 탐색 트리(TreeMap이나 std::map 등)를 사용하며, 이들은 O(log n)입니다. BST는 해시 맵이 제공할 수 없는 순서 보장을 위해 약간의 속도를 희생합니다.
적재율이란 무엇이며 왜 크기 조정을 유발하나요?
적재율은 저장된 항목 수와 버킷 수의 비율입니다. 이것이 올라가면 체인이 길어지고 평균 조회가 느려지므로, 대부분의 구현은 0.75 같은 임계값을 넘으면 크기를 조정합니다(보통 버킷을 두 배로 늘리고 모두 재해싱). 크기 조정은 O(n)이지만 드물기 때문에 상각되어 평균 연산을 O(1)로 유지합니다.
리스트 같은 가변 객체를 해시 맵의 키로 사용할 수 있나요?
보통은 안 됩니다. 키는 해시 가능해야 하고 맵에 있는 동안 해시가 일정해야 합니다 — 예를 들어 Python은 list에 대해 TypeError: unhashable type을 발생시킵니다. 삽입 후 키를 변경하면 해시가 바뀌어 맵이 올바른 버킷에서 더 이상 찾지 못하고 조용히 항목을 잃습니다. 문자열, 숫자, 튜플 같은 불변 키를 사용하세요.
Coddy programming languages illustration

Coddy로 알고리즘을 마스터하세요

시작하기