해시 테이블 (Hash Table)
‘키에 대한 해시 값을 사용하여 값을 저장하고 조회하며, 키-값 쌍의 개수에 따라 동적으로 크기가 증가하는 associate array’
배열 구조로 되어있는 자료 구조이다.
키(key)와 데이터(value)을 짝지어서 저장한다 (키 — 데이터).
이를 통해 찾고자 하는 데이터에 용이하게 접근할 수 있도록 한다.
키: 데이터를 찾을 때 사용하기 위한 (데이터의 인덱싱을 위한) 값으로, 유일하게 존재하며 중복이 불가하다.
데이터: 키를 이용하여 찾을 수 있는 값을 말한다.
실제로 키 값에 해시 함수(hash function)를 적용시켜 데이터를 저장하는 위치가 결정된다.
해시 함수를 만들 때에는 유의할 점이 몇 가지가 있다.
해시 테이블을 이용한 데이터 접근의 시간 복잡도
해시 충돌 (Hash Collision)
만일 혹시라도 해시 함수가 결과값으로 같은 저장 위치를 제공하면, 충돌이 발생한 것이다 (Hash Collision). 충돌을 해결하기 위해서는 세 가지의 방법이 있다.
체이닝(Chaining) - 가장 일반적인 방법
코드 예시 (출처: Programiz)
오픈 어드레싱 (Open Addressing)
•
저장 위치에 이미 데이터가 있으면 새로운 해시 함수를 사용해 다음 저장 위치 (숫자 상으로 표현할 때 1씩 증가)를 확인한다. 순서대로 저장 위치를 찾는 것이라 시간이 많이 걸린다 (군집화).
•
저장 위치에 이미 데이터가 있으면 새로운 함수를 사용해 다음 저장 위치 (고정 아님, 숫자 상으로 표현할 때 현재 반복 횟수의 제곱, 예: 2번째 반복이면 4, 만큼을 더한 위치)를 확인한다.
•
현재 해시 함수 외 제 2의 해시 함수를 사용한다. 위 두 방법과 다르게 군집화 (clustering)을 방지할 수 있다. (똑같이 반복문을 활용해) 2번째 해시 함수가 다음 저장 위치를 얼마나 떨어진 곳으로 할지 결정한다 (반복 횟수 * 해시 함수 값을 더하여).
해시 테이블의 크기는 일정한데 객체의 개수가 계속해서 증가하면 계속해서 충돌이 발생해 궁극적으로 구현 시간이 길어지므로 재해싱 (Rehashing)을 적용해야 한다.
해시 함수 (Hash Function)
해시 함수를 주어진 문자열로 된 키에 적용할 때에는 함수가 생성하는 값의 범위가 넓어야 하며, 하나의 문자에 해시 코드가 좌지우지 되어서는 안된다.
간단한 해시 함수
롤링 해시 (rolling hash)
Java에서의 해시
자바에서는 이미 HashTable과 HashMap이라는 클래스가 구현되어 있다.
(파이썬에서는 Dictionary를 이용해 해시 테이블을 구현할 수 있다.)
HashTable vs HashMap
백엔드에서의 해시
“웹 애플리케이션 서버의 경우에는 HTTPRequest가 생성될 때마다, 여러 개의 HashMap이 생성된다. 수많은 HashMap 객체가 1초도 안 되는 시간에 생성되고 또 GC(garbage collection) 대상이 된다. 컴퓨터 메모리 크기가 보편적으로 증가하게 됨에 따라, 메모리 중심적인 애플리케이션 제작도 늘었다. 따라서 갈수록 HashMap에 더 많은 데이터를 저장하고 있다고 할 수 있다.”