Skip to content

Latest commit

Β 

History

History
173 lines (146 loc) Β· 7.54 KB

Hash.md

File metadata and controls

173 lines (146 loc) Β· 7.54 KB

Hash

효율적인 데이터 관리λ₯Ό μœ„ν•΄, 데이터λ₯Ό κ³ μ •λœ 길이의 λ°μ΄ν„°λ‘œ λ°”κΎΈμ–΄ μ €μž₯ν•˜λŠ” 것

ν•΄μ‹±(Hashing)

  • 킀에 μ‚°μˆ  연산을 μ μš©ν•˜μ—¬ λ‚˜μ˜¨ κ²°κ³Όλ₯Ό μ£Όμ†Œλ‘œ ν•˜μ—¬ 값에 μ ‘κ·Όν•˜λŠ” 방법
  • ν•΄μ‹œ ν…Œμ΄λΈ”μ„ μ΄μš©ν•œ 탐색
  • 킀와 값을 λ§€ν•‘μ‹œν‚€λŠ” κ³Όμ •

ν•΄μ‹œ ν…Œμ΄λΈ”

ν•΄μ‹œν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ ν‚€λ₯Ό ν•΄μ‹œκ°’μœΌλ‘œ λ³€ν™˜ν•˜κ³ , 이 ν•΄μ‹œκ°’μ„ 인덱슀둜 ν•˜μ—¬ 데이터λ₯Ό 킀와 ν•¨κ»˜ μ €μž₯ν•˜λŠ” 자료ꡬ쑰

  • m개의 버킷(bucket)으둜 이루어져 있으며, ν•˜λ‚˜μ˜ 버킷은 s개의 슬둯(slot)을 κ°€μ§ˆ 수 μžˆλ‹€.
  • 자료λ₯Ό μ €μž₯ν•˜λŠ”λ° 배열을 μ‚¬μš©ν•œλ‹€.

ν•΄μ‹œ ν•¨μˆ˜

킀값을 κ³ μ •λœ 길이의 ν•΄μ‹œλ‘œ λ³€κ²½ν•΄μ£ΌλŠ” ν•¨μˆ˜

  • 킀값을 κ·ΈλŒ€λ‘œ μ €μž₯μ†Œμ˜ μƒ‰μΈμœΌλ‘œ μ‚¬μš©ν•  경우 ν‚€μ˜ 길이만큼의 정보λ₯Ό μ €μž₯ν•  곡간도 λ§ˆλ ¨ν•΄μ•Όν•˜κΈ° λ•Œλ¬Έμ—, κ³ μ •λœ 길이의 ν•΄μ‹œλ‘œ λ³€κ²½ν•œλ‹€.

  • 쒋은 ν•΄μ‹œν•¨μˆ˜μ˜ 쑰건

    1. 좩돌 ν™•λ₯ μ΄ 적은 ν•¨μˆ˜
    2. 값을 ν…Œμ΄λΈ” 내에 κ³ λ₯΄κ²Œ 뢄포할 수 μžˆλŠ” ν•¨μˆ˜
    3. 계산이 λΉ λ₯Έ ν•¨μˆ˜

ν•΄μ‹œ 좩돌

μ„œλ‘œ λ‹€λ₯Έ ν‚€κ°€ ν•΄μ‹± ν›„ 같은 ν•΄μ‹œ μ£Όμ†Œλ₯Ό κ°€μ§€λŠ” ν˜„μƒ

  • ν•΄μ‹œ 좩돌이 빈번히 μΌμ–΄λ‚˜μ„œ 빈 버킷이 남지 μ•ŠμœΌλ©΄ μ˜€λ²„ν”Œλ‘œμš°κ°€ μΌμ–΄λ‚œλ‹€ -> ν•΄μ‹œν…Œμ΄λΈ”μ— 값을 μ €μž₯ν•  수 μ—†κ²Œ λœλ‹€.
  • ν•΄μ‹œ μΆ©λŒμ„ μ€„μ΄λŠ” 것이 μ•„μ£Ό μ€‘μš”

ν•΄μ‹±μ˜ μž₯점

  • μ›ν•˜λŠ” ν•­λͺ©μ΄ λ“€μ–΄ μžˆλŠ” μœ„μΉ˜λ₯Ό μ•Œκ³  μžˆλ‹€λ©΄ 맀우 λΉ λ₯΄κ²Œ μžλ£Œμ— μ ‘κ·Ό κ°€λŠ₯ν•˜λ‹€.

    ->이상적인 ν•΄μ‹±μ˜ 경우, O(1)의 μ‹œκ°„λ³΅μž‘λ„λ₯Ό 가진닀.

  • 킀와 κ°’ 사이에 연관성이 μ—†μ–΄ λ³΄μ•ˆμ—λ„ 많이 μ‚¬μš©λœλ‹€.

ν•΄μ‹±μ˜ 단점

  • 데이터가 μ €μž₯되기 전에 미리 곡간을 λ§Œλ“€μ–΄λ†”μ•Όν•˜κΈ° λ•Œλ¬Έμ— 곡간 νš¨μœ¨μ„±μ΄ 떨어진닀.
  • 좩돌이 일어날 κ²½μš°λ²„ν‚· λ‚΄λΆ€μ˜ μˆœμ°¨νƒμƒ‰ μ‹œκ°„μ΄ κΈΈμ–΄μ Έ 탐색 μ„±λŠ₯이 μ €ν•˜λ  수 μžˆλ‹€.
  • 좩돌이 버킷에 ν• λ‹Ήλœ 슬둯 μˆ˜λ³΄λ‹€ 많이 λ°œμƒν•˜κ²Œ 되면 μ˜€λ²„ν”Œλ‘œμš°κ°€ λ°œμƒν•œλ‹€.

이상적인 ν•΄μ‹±

  • 킀와 κ°’μ˜ λͺ¨λ“  경우의 수λ₯Ό λ²„ν‚·μœΌλ‘œ 가지고 μžˆλŠ” 경우

    -> ν•΄μ‹œ ν•¨μˆ˜λ₯Ό κ³„μ‚°ν•˜λŠ” μ‹œκ°„λ§Œ ν•„μš”λ‘œν•œλ‹€. ( 좔가적인 λ°°μ—΄ 탐색이 ν•„μš”μ—†λ‹€.)

μ‹€μ œμ˜ ν•΄μ‹±

  • ν•΄μ‹œ ν…Œμ΄λΈ”μ˜ 크기가 μ œν•œλ˜μ–΄ 있기 λ•Œλ¬Έμ—, ν•˜λ‚˜μ˜ ν‚€λ‹Ή ν•˜λ‚˜μ˜ 곡간을 ν• λ‹Ήν•˜λŠ” 것은 λΆˆκ°€λŠ₯ν•˜λ‹€.
  • 곡간 λ‚­λΉ„λ₯Ό κ³ λ €ν•˜μ—¬, μ‹€μ œλ‘œλŠ” 더 μž‘μ€ ν•΄μ‹œν…Œμ΄λΈ”μ„ λ§Œλ“€μ–΄μ£ΌλŠ” ν•΄μ‹œν•¨μˆ˜λ₯Ό μ΄μš©ν•œλ‹€. -> 좩돌이 μΌμ–΄λ‚˜λŠ” 이유
  • μ‹€μ œμ˜ ν•΄μ‹±μ˜ 경우 μ˜€λ²„ν”Œλ‘œμš°κ°€ 자주 λ°œμƒν•˜κΈ° λ•Œλ¬Έμ— μ‹œκ°„λ³΅μž‘λ„κ°€ O(1)보닀 떨어진닀.

좩돌 ν•΄κ²° 방법

  1. 개방 μ£Όμ†Œλ²•(open addressing): 좩돌이 μΌμ–΄λ‚œ ν•­λͺ©μ„ ν•΄μ‹œ ν…Œμ΄λΈ”μ˜ λ‹€λ₯Έ μœ„μΉ˜μ— μ €μž₯ν•˜λŠ” 방법. λΉ„μ–΄μžˆλŠ” 버킷을 μ°ΎλŠ”λ‹€.

    • μ„ ν˜• 쑰사법: 좩돌이 μΌμ–΄λ‚œ λ²„ν‚·μ˜ λ‹€μŒ 버킷이 λΉ„μ–΄μžˆλŠ”μ§€ ν™•μΈν•˜λŠ” 방법

      • h(k), h(k)+1, h(k)+2 ... 순으둜 탐색
      • 쑰사λ₯Ό μ‹œμž‘ν–ˆλ˜ 곳으둜 λ˜λŒμ•„μ˜¬ λ•ŒκΉŒμ§€ 확인을 κ³„μ†ν•œλ‹€.
      • 킀듀이 μ§‘μ€‘λ˜μ–΄ μ €μž₯λ˜λŠ” ν˜„μƒμ΄ 자주 λ°œμƒν•˜λ©°, μ΅œμ•…μ˜ 경우 μ§‘μ€‘λœ 항ㅁ고이 κ²°ν•©ν•˜λŠ” ν˜„μƒλ„ λ°œμƒν•œλ‹€.
      • μ˜€λ²„ν”Œλ‘œμš°κ°€ 자주 λ°œμƒν•˜λ©΄ 집쀑과 결합에 μ˜ν•΄ 탐색 효율이 크게 μ €ν•˜λœλ‹€.
      //μ„ ν˜• 쑰사법을 μ΄μš©ν•˜μ—¬ ν…Œμ΄λΈ”μ— ν‚€ μ‚½μž…. ν…Œμ΄λΈ”μ΄ 가득 찼을 경우 μ’…λ£Œ
      #define empty(item) (strlen(item.key==0))
      #define equal(item1, item2) (!strcmp(item1.key, item2.key))
      
      void hash_lp_add(element item, emelent ht[])
      {
          int i, hash_value;
          hash_value=i=hash_function(item.key);
          while(!empty(ht[i])){
              if(equal(item, ht[i])){
                  fprintf(stderr, "탐색킀가 μ€‘λ³΅λ˜μ—ˆμŠ΅λ‹ˆλ‹€.\n");
                  exit(1);
              }
              i=(i+1)%TABLE_SIZE;
              if(i==hash_value){
                  fprintf(stderr, "ν…Œμ΄λΈ”μ΄ κ°€λ“μ°ΌμŠ΅λ‹ˆλ‹€.\n");
                  exit(1);
              }
          }
          ht[i]=item;
      }
      
    • 이차 쑰사법: (h(k)+inc*inc)mod M for inc=0, 1, ..., M-1 의 식을 톡해 λ‹€μŒ 쑰사 μœ„μΉ˜λ₯Ό κ²°μ •ν•˜λŠ” 방법

      • h(k), h(k)+1, h(k)+4, h(k)+9 ... 순으둜 탐색
      • μ„ ν˜• μ‘°μ‚¬λ²•μ˜ 집쀑과 결함을 크게 μ™„ν™”μ‹œν‚¬ 수 μžˆλ‹€.
      void hash_qp_add(element item, emelent ht[])
      {
          int i, hash_value, inc=0;
          hash_value=i=hash_function(item.key);
          while(!empty(ht[i])){
              if(equal(item, ht[i])){
                  fprintf(stderr, "탐색킀가 μ€‘λ³΅λ˜μ—ˆμŠ΅λ‹ˆλ‹€.\n");
                  exit(1);
              }
              i=(hash_value+inc*inc)%TABLE_SIZE;
              inc=inc+1;
              if(i==hash_value){
                  fprintln(stderr, "ν…Œμ΄λΈ”μ΄ κ°€λ“μ°ΌμŠ΅λ‹ˆλ‹€.\n");
                  exit(1);
              }
          }
          ht[i]=item;
      }
      
    • 이쀑 해싱법(μž¬ν•΄μ‹±): μ›λž˜μ˜ ν•΄μ‹œν•¨μˆ˜μ™€ λ‹€λ₯Έ λ³„κ°œμ˜ ν•΄μ‹œ ν•¨μˆ˜λ₯Ό μ΄μš©ν•΄ λ‹€μŒ μœ„μΉ˜λ₯Ό μ •ν•˜λŠ” 방법

      • h(k), h(k)+h'(k), h(k)+2*h'(k) ... 순으둜 탐색. (μ—¬κΈ°μ„œ h'(k)=C-(k mod C), CλŠ” ν…Œμ΄λΈ” 크기보닀 μ•½κ°„ μž‘μ€ μ†Œμˆ˜)

      • λ‹€λ₯Έ 방법듀보닀 ν…Œμ΄λΈ”μ— 값을 κ· μΌν•˜κ²Œ λΆ„ν¬μ‹œν‚¬ 수 μžˆμ–΄ νš¨κ³Όμ μ΄λ‹€.

        ->좩돌이 λ°œμƒν–ˆμ„ λ•Œ ν•΄μ‹œκ°’μ— 일정 값을 λ”ν•˜λŠ” λ‹€λ₯Έ 방법듀은 쑰사 μœ„μΉ˜κ°€ 항상 μΌμ •ν•œ 것에 λ°˜ν•΄ ν‚€λ₯Ό μ°Έμ‘°ν•˜μ—¬ 값을 λ”ν•˜λŠ” 이쀑해싱법은 쑰사 μˆœμ„œκ°€ 달라지기 λ•Œλ¬Έ.

      void hash_dh_add(element item, emelent ht[])
      {
          int i, hash_value, inc;
          hash_value=i=hash_function(item.key);
          inc=hash_function2(item.key);
          while(!empty(ht[i])){
              if(equal(item, ht[i])){
                  fprintf(stderr, "탐색킀가 μ€‘λ³΅λ˜μ—ˆμŠ΅λ‹ˆλ‹€.\n");
                  exit(1);
              }
              i=(i+inc)%TABLE_SIZE;
              if(i==hash_value){
                  fprintln(stderr, "ν…Œμ΄λΈ”μ΄ κ°€λ“μ°ΌμŠ΅λ‹ˆλ‹€.\n");
                  exit(1);
              }
          }
          ht[i]=item;
      }
      
  2. 체이닝(chaining): ν•΄μ‹œν…Œμ΄λΈ” ν•˜λ‚˜μ˜ μœ„μΉ˜κ°€ μ—¬λŸ¬ 개의 ν•­λͺ©μ„ μ €μž₯ν•  수 μžˆλ„λ‘ ν•΄μ‹œν…Œμ΄λΈ”μ˜ ꡬ쑰λ₯Ό λ³€κ²½ν•˜λŠ” 방법.

    • 좩돌이 λ°œμƒν•˜λ©΄ μƒˆλ‘œμš΄ λ…Έλ“œλ₯Ό μƒμ„±ν•˜μ—¬ μ €μž₯ν•œλ‹€.
    typedef struct{
        int key;
    } element;
    struct list{
        element item;
        struct list *link;
    };
    struct list *hash_table[TABLE_SIZE];
    
    //체인법을 μ΄μš©ν•˜μ—¬ ν…Œμ΄λΈ”μ— ν‚€λ₯Ό μ‚½μž…ν•˜λŠ” μ½”λ“œ
    void hash_chain_add(element item, struct list *ht[]){
        int hash_value = hash_function(item.key);
        struct list *ptr;
        struct list *node_before = NULL, *node=ht[hash_value];
        for(;node;node_before=node, node=node->link){
            if(node->item.key==item.key){
                fprintf(stderr, "이미 탐색킀가 μ €μž₯돼 있음.\n");
                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;
    }