우규이인우윀
Eager To Learn 🌌
우규이인우윀
전체 방문자
였늘
μ–΄μ œ

λΈ”λ‘œκ·Έ 메뉴

  • 🏑 ν™ˆ
  • πŸš€ κΉƒν—ˆλΈŒ
  • β›… νƒœκ·Έ ν΄λΌμš°λ“œ
  • λΆ„λ₯˜ 전체보기 (217)
    • πŸ‘¨πŸ»β€πŸ’» PS (170)
      • JAVA (82)
      • MYSQL (1)
      • Docker (2)
      • PYTHON (24)
      • LeetCode 150 (39)
      • Algorithm 기법 (1)
      • 바킹독 (21)
    • λΈ”λ‘œκ·Έ 이사 (0)
    • Error (1)
    • CS (15)
      • DataBase (2)
      • OS (7)
      • Network (1)
      • Spring (1)
      • 자료ꡬ쑰 (3)
      • Java (1)
    • Learned (7)
      • Spring (7)
    • κ°œλ°œμ„œμ  (15)
      • 가상 λ©΄μ ‘ μ‚¬λ‘€λ‘œ λ°°μš°λŠ” λŒ€κ·œλͺ¨ μ‹œμŠ€ν…œ 섀계 기초 (1)
      • 였브젝트 - 쑰영호 (7)
      • μΉœμ ˆν•œ SQL νŠœλ‹ (7)
    • 회고 (2)
hELLO Β· Designed By μ •μƒμš°.
우규이인우윀
CS/자료ꡬ쑰

Hash μžλ£Œκ΅¬μ‘°μ™€ ν•΄μ‹œ 좩돌

CS/자료ꡬ쑰

Hash μžλ£Œκ΅¬μ‘°μ™€ ν•΄μ‹œ 좩돌

2023. 9. 5. 08:49

Hash Table μ΄λž€

Hash Table은 데이터λ₯Ό key-value ν˜•μ‹μœΌλ‘œ λ³΄κ΄€ν•˜μ—¬ 검색 Β· μ‚½μž… Β· μ‚­μ œλ₯Ό O(1) μ‹œκ°„ λ³΅μž‘λ„λ‘œ μˆ˜ν–‰ν•  수 μžˆλŠ” μžλ£Œκ΅¬μ‘°μ΄λ‹€.

 

Hash Table은 key 값을 톡해 데이터λ₯Ό 닀루기 λ•Œλ¬Έμ—, key 값은 κ³ μœ ν•΄μ•Όν•œλ‹€.

 

μ΄λŸ¬ν•œ κ³ μœ ν•œ key 값을 λ§Œλ“œλŠ” μž‘μ—…μ€ ν•΄μ‹œ ν•¨μˆ˜κ°€ λ‹΄λ‹Ήν•˜λŠ”λ°,

 

λŒ€ν‘œμ μœΌλ‘œλŠ” key κ°’μ˜ ASCII 값을 ν•©ν•˜μ—¬ λ§Œλ“œλŠ” κ°„λ‹¨ν•œ 방법이 μžˆλ‹€.

 

μ΄λŸ¬ν•œ ν•΄μ‹œ ν•¨μˆ˜κ°€ keyλ₯Ό λ§Œλ“œλŠ” κ³Όμ •μ—μ„œ, μ˜λ„ν•˜μ§€ μ•Šκ²Œ μš°μ—°νžˆ key 값이 μΌμΉ˜ν•˜λŠ” κ²½μš°κ°€ λ°œμƒν•  수 μžˆλŠ”λ°

 

πŸ’‘ 이λ₯Ό ν•΄μ‹œ 좩돌이라고 ν•œλ‹€.

 

ν•΄μ‹œ 좩돌이 λ°œμƒν•˜λ©΄, key 값이 μ€‘λ³΅λ˜μ–΄ 데이터가 μ‚¬λΌμ§ˆ 수 μžˆλ‹€. λ”°λΌμ„œ ν•΄μ‹œ 좩돌이 λ°œμƒν•˜λ©΄ λŒ€μ²˜ν•΄μ•Όν•œλ‹€.

 

λŒ€ν‘œμ μΈ λ°©λ²•μœΌλ‘œλŠ”

 

  1. 체인법 (Seperate Chaning)
  2. μ˜€ν”ˆ μ£Όμ†Œλ²• (Open Addressing) 

두가지 방법이 μžˆλ‹€.

 

ν•΄μ‹œ 좩돌 λŒ€μ²˜λ²•

 

체인법

체인법은 ν•΄μ‹œ 값이 같은 데이터λ₯Ό μ‚¬μŠ¬(chain) λͺ¨μ–‘μ˜ μ—°κ²° 리슀트둜 μ—°κ²°ν•˜λŠ” 방법이닀.

 

μœ„ κ·Έλ¦Όκ³Ό 같이 key 값이 152인 μœ„μΉ˜μ— John Smith 데이터가 μ‘΄μž¬ν•˜λŠ”λ°

 

Sandra Dee μ—­μ‹œ key 값이 152 둜 ν•΄μ‹œ 좩돌이 λ°œμƒν–ˆλ‹€.

 

이런 경우 key 값에 ν•΄λ‹Ήν•˜λŠ” 각 valueλŠ” μ—°κ²°λ¦¬μŠ€νŠΈλ‘œ ꡬ성해놓고, valueκ°€ λ“€μ–΄μ˜¬λ•Œ λ§ˆλ‹€ λ…Έλ“œλ₯Ό μΆ”κ°€ν•΄μ£ΌλŠ” λ°©μ‹μœΌλ‘œ λŒ€μ²˜ν•  수 μžˆλ‹€.

 

🚨 참고둜 μ—°κ²°λ¦¬μŠ€νŠΈλ₯Ό ν‚€ 값을 ν•΄μ‹±ν•œ κ°’μœΌλ‘œ μ°Ύμ•„κ°€κ³ , μ—°κ²°λ¦¬μŠ€νŠΈλ₯Ό μˆœνšŒν•˜λ©΄μ„œ ν•΄μ‹±ν•˜κΈ° μ „ ν‚€ κ°’κ³Ό μΌμΉ˜ν•˜λŠ” λ…Έλ“œκ°€ λ‚˜μ˜¬λ•ŒκΉŒμ§€ νƒμƒ‰ν•˜λŠ” μž‘μ—…μœΌλ‘œ μ›ν•˜λŠ” λ…Έλ“œλ₯Ό 찾을 수 있게 λœλ‹€.

 

Node μ •μ˜

public class ChainHash<K, V> {

    class Node<K, V> {
        private K key;
        private V value;
        private Node<K, V> next;

        public Node(K key, V value, Node<K, V> next) {
            this.key = key;
            this.value = value;
            this.next = next;
        }

        K getKey() {
            return key;
        }

        V getValue() {
            return value;
        }

        public int hashCode() {
            return key.hashCode();
        }
 }

 

κΈ°λ³Έ ꡬ성 틀은 μœ„μ™€ κ°™λ‹€.

 

ν‚€ 값인 K에 ν•΄λ‹Ήν•˜λŠ” 곳에 Node<K,V> λ…Έλ“œ ν΄λž˜μŠ€κ°€ μ‘΄μž¬ν•œλ‹€.

 

그리고 이 λ…Έλ“œλŠ” λ‹€μŒ λ…Έλ“œλ₯Ό μ°Έμ‘°ν•  수 μžˆμœΌλ―€λ‘œ, ν•΄μ‹œ 좩돌이 λ°œμƒν–ˆμ„ λ•Œ next λ³€μˆ˜μ— λ‹€λ₯Έ λ…Έλ“œλ₯Ό μ—°κ²°μ‹œμΌœμ£Όλ©΄ λœλ‹€.

 

 

Hash table μ •μ˜

public class ChainHash<K,V> {

    private int size;
    private Node<K, V>[] table;

    public ChainHash(int size) {
        try {
            table = new Node[size];
            this.size = size;
        } catch (OutOfMemoryError e) {
            this.size = 0;
        }
    }
    
    public int hashValue(Object key) {
        return key.hashCode() % size;
    }
}

이전에 μ •μ˜ν•œ Nodeλ₯Ό ν™œμš©ν•˜μ—¬ ν…Œμ΄λΈ”μ„ μƒμ„±ν•œλ‹€.

 

검색

    public V search(K key) {
        // ν‚€ 값에 ν•΄λ‹Ήν•˜λŠ” ν•΄μ‹œ κ°’μœΌλ‘œ μ ‘κ·Ό
        int hash = hashValue(key);
        Node<K, V> node = table[hash];

        // ν•΄μ‹œκ°’μ— ν•΄λ‹Ήν•˜λŠ” μ—°κ²°λ¦¬μŠ€νŠΈμ— μΌμΉ˜ν•˜λŠ” 킀값을 κ°€μ§„ λ…Έλ“œκ°€ λ‚˜νƒ€λ‚  λ•ŒκΉŒμ§€ 탐색
        while (node != null) {
            if (node.getKey().equals(key)) {
                return node.getValue();
            }
            node = node.next;
        }

        // 검색 μ‹€νŒ¨
        return null;
    }

이전에 μ„€λͺ…ν–ˆλ“―, ν‚€ 값을 ν•΄μ‹±ν•œ κ°’μœΌλ‘œ μ—°κ²°λ¦¬μŠ€νŠΈμ— μ ‘κ·Όν•œλ‹€.

 

μ—°κ²°λ¦¬μŠ€νŠΈμ— μ ‘κ·Όν•΄μ„œλŠ”, ν•΄μ‹±ν•˜κΈ° μ „ ν‚€ κ°’κ³Ό μΌμΉ˜ν•˜λŠ” ν‚€λ₯Ό κ°€μ§„ λ…Έλ“œλ₯Ό λ°œκ²¬ν• λ•ŒκΉŒμ§€ μˆœνšŒν•œλ‹€.

 

μΆ”κ°€

    public int add(K key, V value) {
        int hash = hashValue(key);

        // ν•΄μ‹œκ°’μ— ν•΄λ‹Ήν•˜λŠ” μ—°κ²°λ¦¬μŠ€νŠΈ μ ‘κ·Ό
        Node<K, V> node = table[hash];

        // 빈 λ…Έλ“œλ‘œ μ ‘κ·Ό
        while (node != null) {
            // λ§Œμ•½ μž…λ ₯ν•˜λ €λŠ” ν‚€ 값에 ν•΄λ‹Ήν•˜λŠ” λ…Έλ“œκ°€ 이미 μ‘΄μž¬ν•œλ‹€λ©΄ 
            if (node.getKey().equals(key)) {
                return 1;
            }

            node = node.next;
        }

        // λ…Έλ“œ 생성 ν›„ μž…λ ₯
        Node<K, V> temp = new Node<K, V>(key, value, table[hash]);
        table[hash] = temp;
        return 0;
    }

 

μΆ”κ°€ μ—­μ‹œ, 검색과 μœ μ‚¬ν•˜κ²Œ, ν•΄μ‹œ 값에 ν•΄λ‹Ήν•˜λŠ” λ…Έλ“œλ‘œ μ ‘κ·Όν•΄μ„œ 빈 λ…Έλ“œκ°€ λ‚˜μ˜¬λ•ŒκΉŒμ§€ μ΄λ™ν•œ λ’€

 

λ…Έλ“œλ₯Ό μΆ”κ°€ν•˜λŠ” λ°©μ‹μœΌλ‘œ κ΅¬ν˜„ν•˜λ©΄ λœλ‹€.

 

μ˜€ν”ˆ μ£Όμ†Œλ²•

체이닝 방식은 λ…Έλ“œλ₯Ό 계속 좔가해주닀보면 좔가적인 λ©”λͺ¨λ¦¬λ₯Ό μ‚¬μš©ν•˜κ²Œ λœλ‹€.

 

μ˜€ν”ˆ μ£Όμ†Œλ²•μ€ μΆ”κ°€ 곡간을 μ‚¬μš©ν•˜μ§€ μ•Šκ³  ν•΄κ²°ν•˜λŠ” 방법이닀.

 

πŸ’‘ 좩돌이 일어났을 λ•Œ, μ •ν•΄μ§„ κ·œμΉ™μ— 따라 λ‹€λ₯Έ 자리λ₯Ό μ°Ύμ•„ μ €μž₯ν•˜λŠ” λ°©μ‹μœΌλ‘œ ν•΄μ‹œ μΆ©λŒμ„ λŒ€μ²˜ν•œλ‹€.

 

λŒ€ν‘œμ μœΌλ‘œλŠ” 좩돌이 λ°œμƒν–ˆμ„ λ•Œ μž¬ν•΄μ‹œλ₯Ό μˆ˜ν–‰ν•˜μ—¬ λΉ„μ–΄μžˆλŠ” 버킷을 μ°Ύμ•„λ‚΄λŠ” 방법이 μžˆλ‹€.

 

Bucket μ •μ˜

public class OpenHash<K, V> {
    enum Status {OCCUPIED, EMPTY, DELETED}

    static class Bucket<K, V> {
        private K key;
        private V value;
        private Status status;

        public Bucket() {
            this.status = Status.EMPTY;
        }

        void set(K key, V value, Status status) {
            this.key = key;
            this.value = value;
            this.status = status;
        }

        void setStatus(Status status) {
            this.status = status;
        }

        K getKey() {
            return this.key;
        }

        V getValue() {
            return this.value;
        }

        public int hashCode() {
            return this.key.hashCode();
        }
    }

}

ν•΄μ‹œ ν…Œμ΄λΈ”μ˜ ν•΄μ‹œλ‘œ μ ‘κ·Όν•˜λ©΄ μœ„μ™€ 같은 버킷이 μ‘΄μž¬ν•˜κ³ 

 

각 버킷은 μƒνƒœλ₯Ό λ‚˜νƒ€λ‚΄λŠ” status ν•„λ“œλ₯Ό κ°–λŠ”λ‹€.

 

이 status ν•„λ“œλ₯Ό κ°–λŠ” μ΄μœ λŠ”, 탐색 μ‹œ 재 ν•΄μ‹œ ν•˜λ©΄μ„œ λ²„ν‚·μ˜ 킀와 μΌμΉ˜ν•˜λŠ”μ§€ ν™•μΈν•΄μ•Όν•˜λŠ”λ°

 

3번 μž¬ν•΄μ‹œ 된 데이터λ₯Ό μ°ΎλŠ” 경우, 2번째 μž¬ν•΄μ‹œλœ 데이터가 μ‚­μ œλ˜λ©΄ 데이터λ₯Ό μ°Ύμ§€ λͺ»ν•˜λŠ” κ²½μš°κ°€ λ°œμƒν•  수 있기 λ•Œλ¬Έμ—

 

데이터 μ‚­μ œ μ‹œ, DELETE ν‘œμ‹œλ‘œ μ‚­μ œ 됨을 λ‚˜νƒ€λ‚΄μ£ΌκΈ° μœ„ν•¨μ΄λ‹€.

 

Hash Table μ •μ˜

public class OpenHash<K, V> {

    private int size;
    private Bucket<K, V>[] table;

    public OpenHash(int size) {

        try {
            table = new Bucket[size];
            for (int i = 0; i < size; i++) {
                table[i] = new Bucket<>();
            }
            this.size = size;
        } catch (OutOfMemoryError e) {
            this.size = 0;
        }
    }

    public int hashValue(Object key) {
        return key.hashCode() % size;
    }

    public int rehashValue(int hash) {
        return (hash + 1) % size;
    }
}

이전에 μ •μ˜ν•œ Bucket 을 κ°–λŠ” 배열을 생성해쀀닀.

 

그리고, ν•΄μ‹œ 좩돌 λ°œμƒ μ‹œ λ‹€λ₯Έ ν•΄μ‹œ 값을 λ°˜ν™˜ν•˜λ„λ‘ ν•˜λŠ” rehashValue λ©”μ„œλ“œλ„ μ •μ˜ν•΄μ€€λ‹€.

 

검색

	public V search(K key) {
        Bucket<K, V> bucket = searchNode(key);

        return bucket == null ? null : bucket.getValue();
    }

    private Bucket searchNode(K key) {
        int hash = hashValue(key);
        Bucket<K, V> bucket = table[hash];

		// 버켓이 EMPTY κ°€ μ•„λ‹λ•ŒκΉŒμ§€ 검색, DELETE 된 버킷이어도 검색 μ§„ν–‰ 됨
        for (int i = 0; bucket.status != Status.EMPTY && i < size; i++) {
            if (bucket.status == Status.OCCUPIED && bucket.getKey().equals(key)) {
                return bucket
            }
            hash = rehashValue(hash);
            bucket = table[hash];
        }

        return null;
    }

검색 μ‹œ, λ²„μΌ“μ˜ μƒνƒœκ°€ EMPTY κ°€ μ•„λ‹ˆλΌλ©΄ μž¬ν•΄μ‹œλ₯Ό λ°˜λ³΅ν•΄μ„œ μ›ν•˜λŠ” 킀값을 κ°€μ§„ 버켓이 λ°œκ²¬λ λ•ŒκΉŒμ§€ μ§„ν–‰ν•œλ‹€.

 

μΆ”κ°€

    public int add(K key, V value) {
        // 이미 μ‘΄μž¬ν•˜λŠ” 경우
        if (search(key) != null) {
            return 1;
        }

        int hash = hashValue(key);
        Bucket<K, V> bucket = table[hash];
        for (int i = 0; i < size; i++) {
        	// ν•΄λ‹Ή 버켓이 λΉ„μ–΄μžˆκ±°λ‚˜ DELETED 된 μƒνƒœμΈ 경우 데이터 μΆ”κ°€
            if (bucket.status == Status.EMPTY || bucket.status == Status.DELETED) {
                bucket.set(key, value, Status.OCCUPIED);
                return 0;
            }
            hash = rehashValue(hash);
            bucket = table[hash];
        }

        // ν…Œμ΄λΈ”μ΄ 가득 μ°¬ 경우
        return 2;
    }

μΆ”κ°€ν•˜λŠ” κ³Όμ • μ—­μ‹œ, μž¬ν•΄μ‹œ 과정을 κ±°μΉ˜λ©΄μ„œ λΉ„μ–΄μžˆκ±°λ‚˜ μ‚­μ œλ˜μ–΄ μ‚¬μš©λ˜μ§€ μ•ŠλŠ” 버켓을 μ°Ύκ³ 

 

κ·Έ 버켓에 데이터λ₯Ό μ§‘μ–΄ λ„£λŠ” λ°©μ‹μœΌλ‘œ λ™μž‘ν•œλ‹€.

 

체인법과 μ˜€ν”ˆ μ£Όμ†Œλ²•μ˜ νŠΉμ§•(μž₯단점)

πŸ’‘ κ·Έλ ‡λ‹€λ©΄ 각 λ°©μ‹μ˜ νŠΉμ§•μ„ λ‹€μ‹œ μ •λ¦¬ν•΄λ³΄μž.

 

  1. 체인법
    1. μ—°κ²° 리슀트λ₯Ό μ‚¬μš©ν•˜μ—¬ ν•΄μ‹œμ½”λ“œλ₯Ό λ‹€μ‹œ κ³„μ‚°ν•΄μ•Όν•˜λŠ” μ ˆμ°¨κ°€ ν•„μš”μ—†λ‹€.
    2. νŠΉμ • ν•΄μ‹œ 값에 μ—°κ²° λ¦¬μŠ€νŠΈκ°€ 많이 μΆ”κ°€λ˜λ©΄ μ„±λŠ₯이 μ €ν•˜λ˜κ³  좔가적인 λ©”λͺ¨λ¦¬λ₯Ό μ‚¬μš©ν•˜κ²Œλœλ‹€.
    3. ν•΄μ‹œ ν…Œμ΄λΈ”μ˜ 자체의 크기(λ…Έλ“œ 개수 말고)λ₯Ό λ™μ μœΌλ‘œ μ‘°μ •ν•˜κΈ° μ–΄λ ΅λ‹€.

  2. μ˜€ν”ˆ μ£Όμ†Œλ²•
    1. 좔가적인 λ©”λͺ¨λ¦¬ 곡간이 ν•„μš”μ—†λ‹€.
    2. μ΅œμ•…μ˜ 경우 ν…Œμ΄λΈ” 전체λ₯Ό 검색해야할 수 있고 ν…Œμ΄λΈ”μ˜ λ‘œλ“œ νŒ©ν„°(ν…Œμ΄λΈ”μ˜ 가득 μ°¬ 정도)κ°€ 금방 λ„λ‹¬ν•˜μ—¬ 리사이징이 ν•„μš”ν•  수 μžˆλ‹€.
    3. λ™μ μœΌλ‘œ 크기λ₯Ό μ‘°μ •ν•˜κΈ° 쉽닀.
  • Hash Table μ΄λž€
  • ν•΄μ‹œ 좩돌 λŒ€μ²˜λ²•
  • 체인법
  • μ˜€ν”ˆ μ£Όμ†Œλ²•
  • 체인법과 μ˜€ν”ˆ μ£Όμ†Œλ²•μ˜ νŠΉμ§•(μž₯단점)
'CS/자료ꡬ쑰' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€
  • 병합 μ •λ ¬ (Merge Sort) 을 κ΅¬ν˜„ν•΄λ³΄μž
  • Linked List κ΅¬ν˜„ν•΄λ³΄κΈ°
우규이인우윀
우규이인우윀
개발자 κΏˆλ‚˜λ¬΄

ν‹°μŠ€ν† λ¦¬νˆ΄λ°”

단좕킀

λ‚΄ λΈ”λ‘œκ·Έ

λ‚΄ λΈ”λ‘œκ·Έ - κ΄€λ¦¬μž ν™ˆ μ „ν™˜
Q
Q
μƒˆ κΈ€ μ“°κΈ°
W
W

λΈ”λ‘œκ·Έ κ²Œμ‹œκΈ€

κΈ€ μˆ˜μ • (κΆŒν•œ μžˆλŠ” 경우)
E
E
λŒ“κΈ€ μ˜μ—­μœΌλ‘œ 이동
C
C

λͺ¨λ“  μ˜μ—­

이 νŽ˜μ΄μ§€μ˜ URL 볡사
S
S
맨 μœ„λ‘œ 이동
T
T
ν‹°μŠ€ν† λ¦¬ ν™ˆ 이동
H
H
단좕킀 μ•ˆλ‚΄
Shift + /
⇧ + /

* λ‹¨μΆ•ν‚€λŠ” ν•œκΈ€/영문 λŒ€μ†Œλ¬Έμžλ‘œ 이용 κ°€λŠ₯ν•˜λ©°, ν‹°μŠ€ν† λ¦¬ κΈ°λ³Έ λ„λ©”μΈμ—μ„œλ§Œ λ™μž‘ν•©λ‹ˆλ‹€.