<content>
- 해시함수
- 좋은 해시함수의 특징
- 비둘기집 원리
- 로드 팩터 (load factor)
- 충돌
- separate chaining
- open addressing
해시함수?
- ⭐ 임의 크기 데이터를 고정 크기 값으로 mapping하는데 사용할 수 있는 함수
- 해시테이블의 핵심이다!
해시테이블을 인덱싱하기 위해서 해시함수를 사용하는데, 이것을 해싱(hashing)이라 한다. - 어떠한 입력이든 고정 크기의 값으로 mapping해준다는 의미는
입력이 3글자이든, 4글자이든, 5글자이든 2자리의 숫자로 mapping해줄 수 있다는 의미이다.
좋은 해시함수의 특징
- 해시함수 값 충돌의 최소화
- 쉽고 빠른 연산
- 해시 테이블 전체에 해시 값이 균일하게 분포
- 사용할 키의 모든 정보를 이용하여 해싱
- 해시 테이블 사용 효율이 높은 것
- 좋은 해시함수 예시
- hash table의 사이즈 = 2^n이라고 가정
- 1. key를 2^n으로 나눈 나머지
- 2. 전체 bit pattern을 n개의 구간으로 나누고 XOR 연산을 수행하면서 접는 방법
- 3. key를 제곱한 뒤, n bits를 선택
- 4. key를 다항식에 넣은 뒤, 그 결과를 2^n으로 나눈 나머지
비둘기집 원리
- n개 아이템을 m개 컨테이너에 넣을 때
n>m이라면 적어도 하나의 컨테이너에는 반드시 2개 이상의 아이템들이 들어 있다 - 이것을 해시 테이블과 연관지어 생각해보면
데이터의 수가 n, 버킷의 수가 m일 때 n>m이면 어떤 버킷에는 2개 이상의 데이터가 들어있다는 뜻
로드 팩터
- 로드 팩터란, 해시 테이블에 저장된 데이터의 개수 n을 버킷의 개수 k로 나눈 것
- load factor = n/k
- 로드 팩터의 값에 따라 해시 함수를 재작성해야 될지 아니면 해시 테이블의 크기를 조정해야 할 지 결정한다.
- 또한 로드 팩터의 값은 해시 함수가 key를 잘 분산해주는지 말하는 효율성 측정에서도 사용된다.
- 일반적으로 로드 팩터가 증가할수록 해시 테이블의 성능은 점점 감소한다.
- 자바10의 경우 로드 팩터가 0.75가 넘어설 경우 해시 테이블의 공간을 재할당한다.
해시 함수
- key가 해시 함수를 통과하여 해시 값으로 바뀐다.
- 해시 테이블을 인덱싱하기 위해서 해시 함수를 사용하는 것을 해싱(hashing)이라고 한다.
- 해싱 알고리즘에는 다양한 것들이 있다.
- 해싱 알고리즘 중 가장 단순하면서 널리 쓰이는 것은 정수형 해싱 기법인 modulo-division method이다.
- h(x) = x mod m : 입력값 x를 해시테이블의 크기 m으로 나눈 나머지
- 구글은 해시 함수를 딥러닝으로 학습한 모델을 적용해 충돌을 최소화하는 논문을 발표했다 (!)
충돌
- 아무리 좋은 해시 함수라 하더라도 충돌은 발생한다.
- 여기서 충돌이란, 다른 입력에 대해 동일한 해시값이 나오는 현상을 말한다.
개별 체이닝 (separate chaining)
- 충돌 발생 시, 연결리스트 등 자료구조와 연결하는 방식이다.
- 메모리 할당하여 추가해주면 된다.
- 기본적인 자료구조만 있으면 되기 때문에 개별 체이닝 방식은 인기가 높다.
- C++, 자바는 separate chaining 방식 사용하여 해시 테이블 구현
- 개별 체이닝 방식의 해시 테이블
- 키의 해시 값을 계산한다 (해시 함수 이용)
- 해시 값을 이용해 배열의 인덱스를 구한다.
- 같은 인덱스가 있다면 연결리스트로 연결한다.
- 잘 구현한 경우 대부분의 탐색은 O(1)
- 최악의 경우 (해시 충돌이 계속 발생하는 경우) 탐색은 O(n)이다.
- 자바8에서는 데이터의 개수가 많아지면 red-black tree에 저장하는 형태를 사용하기도 했다.
오픈 어드레싱 (open addressing)
- 충돌 발생 시 탐사를 통해 빈 공간을 찾아나서는 방식이다.
- 무한정 저장할 수 있는 separate chaining 방식과 달리, open addressing 방식은 전체 slot 개수 이상은 저장할 수 없다.
- 모든 원소가 반드시 자신의 해시값과 일치하는 주소에 저장된다는 보장은 없다.
- open addressing에도 여러가지 방법이 있다.
- linear probing
- 충돌이 발생한 경우, 해당 위치부터 순차적으로 탐사를 진행
- 간단하면서 전체적인 성능이 좋은 편이다.
- 하지만 해시 테이블에 저장되는 데이터들이 뭉치는 문제점이 존재 (cluster 형성)
- 해시 테이블 여기저기에 연속된 데이터 그룹이 생기는 현상을 클러스터링이라고 한다.
클러스터끼리 합쳐지면 특정 위치에는 데이터가 몰리고, 다른 위치에는 데이터가 없는 상태가 된다.
이러한 현상은 해시 테이블의 탐색 시간을 증가하게 한다.
- quadratic probing
- 간격이 2차 함수꼴로 증가 (+1, +4, +9, ...)
- linear probing에서 cluster 형성의 문제를 막기 위한 방법
- double hashing
- 현재 hash 값에 또 다른 hash function을 사용하여 이동할 거리를 정한다.
- linear probing
- open addressing 방식은 bucket size보다 큰 경우에는 삽입할 수 없다.
- 따라서 hash table의 일정 비율이상 채워지면 더 큰 크기의 또 다른 bucket을 생성한 후,
여기에 새롭게 복사하는 re-hashing 작업이 일어난다.
separate chaining과 open addressing의 비교
- 일반적으로 open addressing의 방법 중 하나인 선형 탐사는 separate chaining보다 성능이 좋다.
- 하지만 hash table의 80% 이상이 차게 되면 open addressing 방식의 성능은 급격히 저하된다.
- 또한 open addressing 방식은 hash table 크기 이상 저장할 수 없다.
- 따라서 파이썬은 open addressing 방식을 택하되, load factor를 작게 잡아 성능 저하 문제를 해결한다.
chaining | open addressing | |
충돌 해결 | 다른 자료구조 이용하여 해결 | hash table 자체만 이용하여 해결 |
메모리 사용 | pointer size overhead | 오버헤드 없다 |
load factor에 따른 성능 변화 | directly proportional | proportional to (load factor/(1-load factor) |
hash table size보다 더 많은 item 저장 가능 여부 |
가능하다 | 불가능하다 |
hash function 요구사항 | 균등 분포 | 균등 분포 (+ cluster를 피해야 한다) |
removal | 가능 | removals clog the hash table with 'deleted' entries. |
구현 | 간단하다 | 비교적 어렵다 |
www.algolist.net/Data_structures/Hash_table/Open_addressing
* open addressing에서의 삭제
linear probling을 예시로 들겠다.
- hash function(a) = 3 -> 3번 해쉬값에 대응되는 hash table에 값 저장
- hash function(b) = 3 -> 3번 해쉬값에 대응되는 hash table에 이미 값 존재 -> 4번 비어있으므로 4번에 저장
- hash function(c) = 3 -> 3번 이미 존재 -> 4번도 이미 존재 -> 5번 비어있으므로 5번에 저장
- 이 때, index 4에 저장된 값을 지워버리면 index 5번에 저장된 값을 찾아갈 수 없다.
- 왜냐하면 hash function(c) = 3이 나왔을 때 3 찾고 없으면 4를 찾아보는데
이 때 4번이 비어있으면 더이상 탐색을 하지 않기 때문이다. - 만약에 4번이 비어있어도 4번을 다음을 search하게 하려면 search의 성능이 O(N)이 되버린다.
- 따라서 삭제하는 것을 지원하지 않기도 한다.
- 왜냐하면 hash function(c) = 3이 나왔을 때 3 찾고 없으면 4를 찾아보는데
언어별 해시 테이블 구현 방식
- 파이썬에서 해시 테이블로 구현된 자료형은 딕셔너리
- 파이썬의 해시 테이블은 open addressing 방식이다.
- separate chaining은 추가 메모리 할당이 필요한데, 이 과정은 상대적으로 느리기 때문에 선택 X
- C++ : separte chaining
- 자바 : separate chaining
'다전공_컴퓨터공학 > 자료구조, 알고리즘' 카테고리의 다른 글
[알고리즘] DFS, BFS (0) | 2020.12.25 |
---|---|
[자료구조] 그래프 순회 (graph traversals), 그래프 표현 (0) | 2020.12.25 |
[자료구조] Heap (python heapq) (0) | 2020.12.20 |
[인공지능] 균일비용탐색 / 최상우선탐색 / A* 알고리즘 (0) | 2020.12.20 |
[자료구조] 우선순위 큐 (priority queue) (0) | 2020.12.20 |