테이블 (table) :
데이터를 구조화해 저장하는 자료구조로 key-value 쌍으로 데이터를 입력 받아 키를 입력해 해당 쌍의 데이터를 찾아온다.
해시 테이블:
→ 충돌이 없다면 데이터를 한 번에 찾을 수 있어 효율적인 탐색( 빠른 탐색 ) 을 위한 자료구조이다.
해시 테이블은 빠른 검색 속도를 제공하며, 삽입과 삭제 연산도 상수 시간에 가깝게 수행될 수 있어 많은 데이터를 효율적으로 처리할 때 유용하다. 그러나 해시 함수의 선택과 충돌 해결 방법의 올바른 구현이 중요하며, 최악의 경우 충돌이 많이 발생할 경우 성능이 저하될 수 있다.
직접 주소화 테이블
배열을 사용해 각 키에 대한 인덱스를 사용하여 키-값 쌍을 저장하는 자료구조, key 값으로 k를 갖는 원소는 인덱스 k에 저장
키의 범위가 작고 연속적인 경우에 유용하며, 키를 직접 인덱스로 사용하여 배열에 접근하여 값을 저장하거나 검색할 수 있다.
직접 주소화 테이블은 저장할 수 있는 키의 범위가 제한되어 있어 공간 복잡도가 상대적으로 높을 수 있다. 예를 들어, 키의 범위가 0부터 m까지이면 배열의 크기는 m+1이 된다.
→ 즉 불필요한 공간의 낭비가 발생
직접 주소화 테이블은 키를 배열의 인덱스로 사용하여 바로 해당 위치에 접근하여 값을 저장하거나 검색할 수 있다. 따라서 데이터를 검색하거나 삽입하는 데 걸리는 시간 복잡도는 O(1) 즉, 상수 시간에 해당한다.
문제:
해시 함수 h를 이용해 (key, value) 를 index : h(k) 에 저장
키 k 값을 가지는 원소가 위치
h(k)에 해시된다.
h(k)는 키 k의 해시값이다.
collision ( 충돌 ):
서로 다른 키의 해시값이 같은 상황, 중복되는 key는 없지만 해시 값이 중복되어 같은 데이터를 가리키는 상황
해결
인덱스 위치가 충돌한다면 정한 규칙에 따라 빈 슬롯을 찾을 때까지 검사
추가적인 메모리 공간이 필요 없고 테이블이 가득 차면 삽입이 어렵다.
인덱스 위치가 충돌한다면 빈 slot을 찾을 때까지 내려간다. 배열의 끝에 도달하면 다시 처음으로 돌아가서 빈 slot을 탐색 (wrapping around : 배열을 원형으로 생각해 탐색)
충돌이 발생했을 때 현재 위치에서부터 일정한 간격을 이용하여 다음 위치를 찾는 방법
두 개의 해시 함수를 사용하여 충돌을 해결하는 방법
충돌이 발생했을 때 두 번째 해시 함수를 사용하여 다음 위치를 결정한다. 이때 두 번째 해시 함수는 키와 상관없이 일정한 범위 내에서 값을 반환해야 한다.
이중 해싱은 충돌된 위치에서부터 일정한 간격이 아닌 다른 위치로 이동하기 때문에 클러스터링 문제를 해결할 수 있다.
또한, 두 번째 해시 함수가 독립적으로 정의되기 때문에 일정한 패턴이 나타나지 않아 빈 슬롯을 더 쉽게 찾을 수 있다.
→ 하나의 해시함수는 최초의 해시값을 얻을 때 사용, 또 하나는 해시 충돌이 발생할 때 탐사 이동폭을 얻기 위해 사용
해시 테이블에서 충돌 발생 시 각 해시에 해당하는 slot에 linked list를 추가해 데이터를 저장, 추가적인 메모리 공간 사용
해시 테이블의 크기가 고정되어 있을 때에도 효율적으로 동작하며, 연결 리스트의 구현 방법에 따라 메모리 소비를 최적화할 수 있다.
충돌된 데이터들은 연결 리스트의 형태로 슬롯에 저장되고, 이를 통해 동일한 해시 값에 대한 다수의 데이터를 하나의 슬롯에 저장할 수 있다.
장점
🎯 개별 체이닝은 기본적으로 linked list를 이용해 데이터를 저장하지만 충돌이 많이 발생해 연결 리스트의 길이가 길어지면 BST 자료구조로 데이터를 저장하기도 한다.
→ BST를 사용해 worst case의 시간복잡도를 O(n) → O(logn)으로 낮출 수 있다.
n개의 모든 키가 동일한 해시값을 가져 길이 n의 연결리스트가 생성되는 경우
특정 키를 찾기 위해서는 길이 n의 연결리스트를 검색하는 O(n)의 시간복잡도와 동일하게 된다.