hash
는 내부적으로 배열
을 사용해 데이터를 저장해 빠른 검색 속도hashcode
라고 함collision
이라 부름collistion
: 서로 다른 두 개의 키가 같은 인덱스로 hashing되면 같은 곳에 저장할 수 없음collision을 피해야하는 hash function
의 조건
일반적으로 좋은 hash function
은 키의 일부를 참조해 해시 값을 만들지 않고 키 전체를 참조해 해시 값을 만들어 냄. 하지만, 좋은 해시 함수는 키의 특성을 따름
hash function
을 무조건 1:1 로 만드는 것보다 collision을 최소화하는 방향으로 설계하고발생하는 collision을 대응하는 것이 더 중요
1:1로 대응되는 것이 거의 불가능하고 그런 hash function
을 만들어봤자 일반적인 배열과 다른 점이 없고 메모리를 많이 차지하게 됨
collision이 많아질 수록 검색시 시간 복잡도가 O(1) -> O(n) 에 가까워짐
hashing된 인덱스에 이미 다른 값이 있다면 새 데이터를 저장할 다른 위치를 찾은 뒤에 저장할 수 있음 -> 충돌 해결
기본적인 2가지 방법
해시 충돌이 발생하면, 다른 해시 버킷에 해당 자료를 삽입하는 방식
다른 해시 버킷을 찾는 방법 3가지
1. Linear Probing 순차적으로 탐색해 비어있는 버킷을 찾을 때까지 진행
2. Quadratic probing 2차 함수를 이용해 탐색 위치 찾음
3. Double hashing probing 하나의 해시 함수에서 충돌 발생시 2차 해시함수를 사용해 새로운 주소 할당
일반적으로 Open Addressing은 Separate Chaning보다 느림
개방 주소의 경우 해시 버킷을 채운 밀도가 높아질수록 Worst case 발생 빈도가 높아짐
반면, 분리 연결 방식은 해시 충돌이 잘 발생하지 않도록 보조 해시 함수를 통해 조절할 수 있다면 Worst case에 가까워 지는 빈도를 줄일 수 있음 Java7의 경우 해당 방식 사용해 HashMap 구현
Separate Chaining 방식의 2가지 구현 방식
데이터가 적다는 것의 기준? - key-value 쌍의 개수.
6개와 8개로 나뉨
7은 어디로??? 6개에서 7이 되면 트리가 되고 7에서 6이 되면 링크드리스트로 변경하면 비용이 너무 많이 할당됨.
둘 다 worst case에서 O(m)
Open address는 연속된 공간에 데이터가 저장되기 때문에 캐시 효율이 높음
데이터의 개수가 충분히 적은 경우 open address를 사용하는 것이 좋음
key의 해시 값을 변형해 해시 충돌 가능성을 줄임
separate chaining 방식을 사용할 때 함께 사용되며 worst case 에 가까워지는 경우를 줄여줌
해시 버킷의 개수가 적으면 메모리 사용을 줄일 수 있지만 충돌이 발생할 확률이 상승.
hash map은 key-value 데이터 개수가 일정 개수 이상이 되면 해시 버킷의 개수를 두배로 늘려 ㅊ충돌 문제를 어느정도 해결