교수님이 쓰라고 하셔서 쓰는 그런데 은근 재밌는 듯

자료구조

[자료구조] 해싱

shinyunha 2025. 12. 9. 20:35

키 값을 input으로 output이 특정 범위 내로 나오도록 연산을 수행한다. 이 결과를 주소로 hash table의 항목에 접근한다.

저장/ 탐색 모두 O(1), 최악의 경우 O(n)

Dictionary(사전구조)

map또는 table로 불리며 탐색 키value, 2가지 필드로 구성된다.   


hash function (해시 함수)

탐색 키를 입력받아 hash address(해시 주소)를 생성

hash address가 hash table의 index

+ hash value: 해시 함수의 결과값

 

Prime Number Modular Function (제산함수)

h(k) = k mod M

M: 해시 테이블 크기, 소수(prime number)로 선택

 

비트추출 함수

M = 2^k일 때, 임의의 위치의 k개의 비트를 이진수로 간주하여 해시 주소로 사용


hash table(해시 테이블)

M개의 bucket으로 구성된 table, 각 bucket은 s개의 slot으로 이루어짐

 

충돌(collision): 서로 다른 두 개의 탐색키의 hash address가 같을 때, 즉 h(k1) == h(k2)

오버플로우(overflow): 충돌이 버켓의 슬롯 수보다 많이 발생

 

실제로는 collision & overflow를 해결하기 위한 알고리즘 추가

-> O(1) + ɑ


충돌 해결책

Linear Probing (선형조사법)

충돌이 일어난 바로 다음 칸을 조사 (비어있는 공간이 나올 때까지)

테이블의 끝에 도달하면, 테이블의 처음부터 조사

조사 시작 위치로 돌아오면 테이블이 가득 찬 것

 

단점:

군집화(clustering) - collision이 한 번 시작되면 그 주위에서 계속 발생

결합(coalescing) - cluster들이 합쳐짐 

//문자로 된 키를 숫자로 변환
int transform(char* key){
    int number = 0;
    
    while(*key){
        number += (int)*key;
        key++;
    }
    
    return number;
}
int hash_function(char* key){
    //키를 자연수로 변환하고 테이블의 크기로 나누어 나머지를 반환
    return transform(key)%TABLE_SIZE;
}
void hash_lp_add(element item, element ht[]){
    int i, hash_value;
    hash_value = i = hash_function(item.key);
    
    while(!empty(ht[i])){ //slot이 비어있는 버켓을 찾을 때까지
        //item이 이미 hash table에 있음
        if(equal(item, ht[i])){
            //탐색키 중복
            exit(1);
        }
        
        //collision
        i = (i+1)%TABLE_SIZE;
        
        //출발 지점으로 돌아옴
        if(i == hash_value){
            //테이블이 가득참
            exit(1);
        }
    }
    
    //삽입
    h[i] = item;
}

Quadratic Probing (이차조사법)

다음 조사할 위치: ( h(k) + inc*inc ) mod M

inc는 1씩 커짐

군집과 결합 크게 완화 가능

 

단점: h(k)가 같은 키에 대해서는 계속 collision 발생

int inc = 0;

i = (i + inc*inc) % TABLE_SIZE;
inc++;

Double Hashing (이중 해싱법) 

rahashing(재해싱)이라고도 함

 

오버플로우가 발생하면 원 해시함수와 다른 별개의 해시 함수 사용

이차조사법처럼 같은 패턴 반복되지 않음

 

ex)

h'(k) = C - (k mod C) 

C는 M보다 작은 소수

 

h(k) -> collision -> h(k)+h'(k) -> collision -> h(k) + 2h'(k) -> collision -> h(k) + 3h'(k) ....


Chaining (체이닝)

오버플로우 문제를 연결 리스트로 해결

각 버켓에 고정된 슬롯을 할당하는 게 아니라, 연결 리스트를 할당

충돌 나면 새로운 노드 생성해서 저장

void hash_chain_add(element item, struct list *ht[]){
    int hash_value = hash_function(item.key);
    
    struct list *ptr;
    struct list *node_before = NULL;
    struct list *node = ht[hash_value];
    
    for(; node; node_before = node, node = node->link){
        if(node -> item.key == item.key){
            //이미 탐색키가 저장되어 있음
            return;
        }
    }
    
    ptr = (struct list*)malloc(sizeof(struct list));
    ptr->item = item;
    ptr->link = NULL;
    
    if(node_before) node_before->link = ptr;
    else ht[hash_value] = ptr;
}

'자료구조' 카테고리의 다른 글

[자료구조] 탐색  (0) 2025.12.07
[자료구조] 정렬  (0) 2025.12.06
[자료구조] 그래프  (0) 2025.12.04
[자료구조] Heap  (0) 2025.10.28
[자료구조] 트리  (0) 2025.10.27