Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 |
Tags
- 백준
- @Retryable
- ajax
- 단일db cqrs
- 1정규화
- 구간합구하기
- 2차원배열 구간합
- select
- 2정규화
- 백준 11660번
- 트랜잭션 동시성 이슈
- 다중db cqrs
- SQL
- 교차 출처 리소스 공유
- 3정규화
- 구간합
- sop 우회
- jquery
- json
- Java
- boj21891
- lock-based
- 12891번
- this
- 생성자
- cross origin resources sharing
- map()
- 멀티스레드
- cas알고리즘
- segregation
Archives
- Today
- Total
평범한 연구소
해시와 해시 충돌 본문
해시 (Hash)
- key, value 쌍으로 이루어진 데이터 구조
- 키를 이용해 값을 O(1) 시간 복잡도로 찾을 수 있다.
해시 충돌 (Hash Collision)
- 다른 key를 사용해도 같은 결과가 나오는 경우를 해시 충돌이라고 한다.
- 해시 충돌을 완화하기 위한 접근 방법
- 개방 주소법
- 분리 연결법
개방 주소법 (Open Addressing)
- 특정 값이 들어가야하는 자리(버킷)가 이미 사용되고 있는 경우, 다른 빈 공간을 탐색하여 버킷에 데이터를 삽입한다.
- 대표적인 3가지 방식이 있다.
- 선형 탐사 (Liner Probing)
- 고정된 크기만큼 한 칸씩 옮기면서 빈 버킷을 찾는 방법
- 해시 자료 구조 전체에서 해시 충돌이 균등하게 발생하는 경우 유리한 탐색법이다.
- 구현이 간단하고 캐시 적중률이 높으나 특정 버킷 주변이 모두 채워져 있는 경우, 성능이 저하될 수 있다. (클러스터링=군집화 문제)
- 충돌 시 index+1, index+2 ... 순차적으로 탐색
- 충돌: h(k), 다음 h(k)+1, h(k)+2 ...
- 제곱 탐색 (Quadratic Probing)
- 한 칸씩 찾는 것이 아닌, 제곱만큼 늘리면서 빈 버킷을 찾는다.
- 점점 늘어나기 때문에 선형 탐색처럼 특정 영역에 값이 밀집되어 저장되어도 해당 영역을 빠르게 벗어날 수 있다.
- 선형탐사에 비해 군집화가 감소되나 여러 값이 해시 함수로 같은 값을 갖게될 경우, 모두 같은 순서로 탐사하기 때문에 충돌이 많으면 공간이 낭비된다.
- index+1^2, index+2^2, index+3^2 ...
- 덜 밀집되게 분포되도록
- 이중 해시 (Double Hashing)
- 보조 해시 함수를 사용하는 방법
- 충돌 분산, 충돌 가능성이 가장 낮지만 추가 보조 해시 함수를 사용하여 연산이 발생하고 구현이 복잡하다.
- h(k, i) = (h1(k) + i * h2(k)) % tableSize
- 더 넓은 범위로 분산 가능
- 선형 탐사 (Liner Probing)
분리 연결법 (Seprate Chaining)
- 버킷 내에 연결 리스트(Linked List)를 할당하여, 버킷에 데이터를 삽입하다가 해시 충돌이 발생하면 연결 리스트로 데이터들을 연결하는 방식
- 충돌 시 동일한 인덱스에 연결리스트로 저장
- 버킷을 연결 리스트나 트리 형태로 관리하여 버킷에 들어갈 값의 수에 제한을 두지 않도록 하여 충돌을 완화한다.
개방 주소법의 장점
- 포인터가 필요 없고, 저장한 메모리 외의 추가 공간이 필요하지 않다.
- 삽입/삭제 시 오버헤드가 적다
- 저장할 데이터가 적은 경우에 유리
분리 연결법의 장점
- 연결 리스트만 사용하면 된다 = 개방주소법에 비해 복잡한 계산식을 사용할 필요가 적다.
아래는 선형 탐사 예제 🙂
package hashCollision;
public class OpenAddressingHashTable {
// 선형 탐사 예제
private Integer[] table;
private int size;
public OpenAddressingHashTable(int size) {
this.size = size;
this.table = new Integer[size];
}
private int hash(int key) {
return key % size;
}
public void insert(int key) {
int index = hash(key);
int startIndex = index;
while (table[index] != null) {
index = (index + 1) % size;
if(index == startIndex) throw new RuntimeException("Table is full");
}
table[index] = key;
}
public boolean search(int key) {
int index = hash(key);
int startIndex = index;
while (table[index] != null) {
if(table[index].equals(key)) return true;
index = (index + 1) % size;
if(index == startIndex) break;
}
return false;
}
public void showTable() {
for(int i=0; i<size; i++) {
System.out.println(i + ": " + table[i]);
}
}
public static void main(String[] args) {
OpenAddressingHashTable hashTable = new OpenAddressingHashTable(7);
hashTable.insert(10);
hashTable.insert(24);
hashTable.insert(17);
hashTable.showTable();
}
}'Back' 카테고리의 다른 글
| 멀티스레드 환경에서의 동시성 이슈 (CAS 알고리즘) (0) | 2025.07.02 |
|---|---|
| static과 Been, @Transactional에 대해 (0) | 2023.07.13 |
| Unit Test와 Function Test (0) | 2023.07.12 |
| [MariaDB] sql 파일 import 하기 (0) | 2023.03.17 |
| [Spring] 엔티티와 is~() (자바빈 규약) (0) | 2023.03.14 |