해싱
해싱은 키값을 비교하는 것이 아니라 탐색키에 산술적인 연산을 적용하여 항목이 저장되어 있는 위치, 즉 인덱스를 직접 계산하는 방식이다. 이렇게 키값의 연산에 의해 직접 접근이 가능한 구조를 해시 테이블(hash table)이라 하며, 해시 테이블을 이용한 탐색을 해싱(hashing)이라 한다.
예를 들어 탐색키들이 모두 1 ~ 1000 사이의 정수라고 가정해보자. 그렇다면 가장 빠르게 자료를 저장하고 꺼낼 수 있는 방법은 1000개의 요소를 가지는 배열을 만드는 것이다. 자료의 삽입과 탐색은 탐색키를 배열의 인덱스로 생각하고 단지 배열의 특정 요소를 읽거나 쓰면 된다. 이들 연산은 명백하게 이다. 이것이 해싱의 기본 아이디어이다.
현실적으로는 탐색키들이 문자열이거나 굉장히 큰 숫자이기 때문에 탐색키를 직접적으로 배열의 인덱스로 사용하지 못하고 각 탐색키를 작은 정수로 사상(mapping)시키는 어떤 함수가 필요하다. 이것을 해시 함수(hash function)라고 한다. 해시 함수는 탐색키를 입력 받아 해시 주소(hash address)를 계산하는데, 삽입이나 삭제, 탐색 연산은 모두 이 주소에서 이루어진다.
해시 테이블은 버켓(bucket)으로 이루어지는 테이블이고, 하나의 버켓에는 각각 레크드를 저장할 수 있는 여러 개의 슬롯(slot)을 가진다. 이것은 여러 개의 탐색키가 동일한 해시 주소로 변환될 수 있기 때문이다.
해시 테이블의 버켓의 수가 제한적이므로 경우에 따라 서로 다른 키 k1 과 k2 가 해시함수에 의해 같은 주소, 즉 h(k1) == h(k2) 로 계산되는 상황이 발생한다. 이것을 충돌(collision)이라고 하고, 이러한 키 k1 과 k2 를 동의어(synonym)라 한다.
충돌이 발생하면 어떻게 할까? 만약 버켓에 여러 개의 슬롯이 있다면 k1 과 k2 를 각각 다른 슬롯에 저장하면 된다. 그러나 충돌이 슬롯 수보다 더 많이 발생할 수도 있는데, 이러한 상황을 오버플로우(overflow)라고 한다. 이 경우 해당 버켓에 더 이상 항목을 저장할 수 없게 된다. 따라서 해싱에서는 오버플로우를 해결하기 위한 방법이 반드시 필요하다.
- 해시 함수
좋은 해시 함수의 조건은 다음의 3가지이다.
- 충돌이 적어야 한다.
- 해시 함수 값이 해시 테이블의 주소 영역 내에서 고르게 분포 되어야 한다.
- 계산이 빨라야 한다.
- 제산 함수
가장 일반적인 방법이 나머지 연산자 mod(C++에서 % 연산자)를 사용하는 것이다. 테이블의 크기가 M일 때 탐색키 k에 대하여 해시 함수는 다음과 같다.
h(k) = k mod M
이때, 가능하면 해시 주소를 더 고르게 분포시키기 위해 해시 테이블의 크기 M은 소수(prime number)를 선택한다. 즉, 1과 자기 자신만을 약수로 가지는 수라면 K mod M 은 0에서 M - 1 을 골고루 사용하는 값을 만들어 낸다.
- 폴딩 함수
- 중간 제곱 함수
- 비트 추출 방법
- 숫자 분석 방법
- 탐색키가 문자열인 경우
#pragma once
#ifndef ___HashFunctions
#define ___HashFunctions
// hashFunctions.h : inline 해시 함수들
#define TABLE_SIZE 13 //해싱 테이블의 크기 (소수를 사용)
// 문자열로 된 탐색키를 숫자로 변환 : 간단한 덧셈 방식
inline int transform(const char* key) {
int number = 0;
while (*key)
number += (*key);
return number;
}
// 해싱 함수 : 제산 함수 사용
inline int hashFuntion(char *key) {
return transform(key) % TABLE_SIZE;
}
#endif // !___HashFunctions
물론 최종적인 해시 주소는 문자열을 정수로 변환한 값에 해시 함수를 적용하여 만들어진다. 위에서 hashFunction() 함수는 제산 함수를 사용하였다.
'Programming > DS SorceCode' 카테고리의 다른 글
HashMap.h : 해싱을 이용하는 맵 클래스 #오류 있음 (0) | 2019.04.06 |
---|---|
HashRecord.h : 해시 맵을 위한 keyed Record 클래스 (0) | 2019.04.06 |
AVL 트리 (0) | 2019.04.05 |
Search.h : 다양한 탐색 함수를 포함함 헤더 (0) | 2019.04.04 |
Sorting.h : 다양한 정렬을 포함한 헤더 (0) | 2019.04.04 |