7.1 ํด์ ํ ์ด๋ธ์์์ ์ถฉ๋ ์ ์
ํด์ ํ ์ด๋ธ์์์ ์ถฉ๋์ ๋ ๊ฐ์ ๋ค๋ฅธ ํค๊ฐ ๊ฐ์ ๋ฐฐ์ด ์ธ๋ฑ์ค๋ก ํด์ฑ๋ ๋ ๋ฐ์ํด. ์ด๋ ๊ฒ ๋๋ฉด ๋ ๊ฐ ์ด์์ ์์๊ฐ ๊ฐ์ ํด์ ํ ์ด๋ธ ์ ์ ์ฐจ์งํ๋ ค๊ณ ํด.
์ถฉ๋์ ์:
๊ฐ๋จํ ํด์ ํจ์๊ฐ ํ
์ด๋ธ ํฌ๊ธฐ์ ๋ํ ํค์ ๋๋จธ์ง๋ฅผ ๋ฐํํ๋ค๊ณ ๊ฐ์ ํด ๋ณด์. ํ
์ด๋ธ ํฌ๊ธฐ๊ฐ 10์ผ ๋ ํค 5์ 15๋ ๋์ผํ ์ธ๋ฑ์ค๋ฅผ ์ฃผ๊ฒ ๋ผ: 5 % 10 = 5
์ 15 % 10 = 5
. ์ด๊ฒ์ด ์ถฉ๋์ด์ผ.
๋ ๋ค๋ฅธ ์:
์ด๋ฆ ์ฌ์ ์ ์์ฑํ๋ค๊ณ ๊ฐ์ ํด, ๊ทธ๋ฆฌ๊ณ ์ฒซ ๋ฒ์งธ ๋ฌธ์๋ฅผ ๋ฐํํ๋ ๊ฐ๋จํ ํด์ ํจ์๋ฅผ ๊ฐ์ง๊ณ ์์ด. ๊ทผ๋ฐ ์ด๋ฆ์ 80%๊ฐ "A"๋ก ์์ํ๋ฉด, ์ด๊ฑด ๋จ์ํ ์ถฉ๋์ด ์๋๋ผ ๋ฌธ์ ์ผ.
7.2 ์ถฉ๋ ํด๊ฒฐ ๋ฐฉ๋ฒ โ ์ฒด์ด๋
ํด์ ํ ์ด๋ธ์์ ์ถฉ๋์ ํด๊ฒฐํ๋ ์ฌ๋ฌ ๊ฐ์ง ๋ฐฉ๋ฒ์ด ์์ด. ๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ ์ฒด์ด๋(chaining)๊ณผ ์คํ ์ด๋๋ ์ฑ(open addressing)์ด์ผ.
์ฒด์ด๋ (Chaining)
์ฅ์ :
- ๊ตฌํ์ด ์ฝ๋ค.
- ์ถฉ๋์ด ์ ์ ๊ฒฝ์ฐ ํจ์จ์ ์ด๋ค.
- ํด์ ํ ์ด๋ธ ๋ฐ๋์ ๋ ์์กด์ ์ด๋ค.
๋จ์ :
- ์ฐ๊ฒฐ ๋ฆฌ์คํธ์ ํฌ์ธํฐ๋ฅผ ์ํ ์ถ๊ฐ ๋ฉ๋ชจ๋ฆฌ๊ฐ ํ์ํ๋ค.
- ์ถฉ๋์ด ๋ง์ ๊ฒฝ์ฐ ๊ธด ์ฒด์ธ์ผ๋ก ์ธํด ์ฑ๋ฅ์ด ๊ฐ์ํ ์ ์๋ค.
์ฒด์ด๋ ๋ฐฉ๋ฒ ๊ตฌํ ์์ :
insert ํจ์์ ์๋ ๋ฐฉ์์ ๋ฐฐ์ฐ๊ธฐ๋ง ํ๋ฉด ๋์ง๋ง, ํธ์๋ฅผ ์ํด ์ ์ฒด ์ฝ๋๋ฅผ ์ ๊ณตํ ๊ฒ.
class HashTableChaining:
def __init__(self, size):
self.size = size
self.table = [None] * size
def hash_function(self, key):
return hash(key) % self.size
def insert(self, key, value):
index = self.hash_function(key)
if self.table[index] is None:
self.table[index] = [(key, value)]
else:
for i, kv in enumerate(self.table[index]):
k, v = kv
if k == key:
self.table[index][i] = (key, value)
return
self.table[index].append((key, value))
def search(self, key):
index = self.hash_function(key)
if self.table[index] is None:
return None
for k, v in self.table[index]:
if k == key:
return v
return None
def delete(self, key):
index = self.hash_function(key)
if self.table[index] is None:
return
for i, kv in enumerate(self.table[index]):
k, v = kv
if k == key:
del self.table[index][i]
return
# ์ฌ์ฉ ์์ :
hash_table = HashTableChaining(10)
hash_table.insert("apple", 1)
hash_table.insert("banana", 2)
hash_table.insert("cherry", 3)
print(hash_table.search("banana")) # ์ถ๋ ฅ: 2
hash_table.delete("banana")
print(hash_table.search("banana")) # ์ถ๋ ฅ: None
7.3 ๋ ๋ฒ์งธ ๋ฐฉ๋ฒ โ ์คํ ์ด๋๋ ์ฑ
์คํ ์ด๋๋ ์ฑ ๋ฐฉ๋ฒ์ ์ถฉ๋ ์ ๋ฐฐ์ด์ ๋ค์ ์ฌ์ฉ ๊ฐ๋ฅํ ์ ์ ์ฐพ๋๊ฑฐ์ผ. ์ฌ๋ฌ ์ ๋ต์ด ์์ด: ์ ํ ํ์ฌ, ์ ๊ณฑ ํ์ฌ ๋ฐ ์ด์ค ํด์ฑ.
์ฅ์ :
- ํฌ์ธํฐ ์ ์ฅ์ ์ํ ์ถ๊ฐ ๋ฉ๋ชจ๋ฆฌ๊ฐ ํ์ ์๋ค.
- ๋ ์ปดํฉํธํ ๋ฐ์ดํฐ ํํ.
๋จ์ :
- ํ ์ด๋ธ ๋ฐ๋๊ฐ ๋์ ๋ ์ฑ๋ฅ์ด ํฌ๊ฒ ๋จ์ด์ง ์ ์๋ค.
- ์ถฉ๋ ํด๊ฒฐ์ ์ํด ๋ ๋ง์ ๊ณ์ฐ ์์์ด ํ์ํ๋ค.
์คํ ์ด๋๋ ์ฑ ์ ๋ต ์์
์ ํ ํ์ฌ (Linear Probing):
- ๋จ๊ณ๊ฐ 1์ธ ํ์ฌ:
index = (index + 1) % size
. - ๊ฐ๋จํ์ง๋ง "ํด๋ฌ์คํฐ๋ง"์ ์ ๋ฐํ ์ ์๋ค.
์ ๊ณฑ ํ์ฌ (Quadratic Probing):
- ๋จ๊ณ๊ฐ ์ ๊ณฑ์ผ๋ก ์ฆ๊ฐํ๋ ํ์ฌ:
index = (index + i^2) % size
. - ํด๋ฌ์คํฐ๋ง ๋ฌธ์ ๋ฅผ ์ค์ด์ง๋ง ๊ตฌํ์ด ๋ ๋ณต์กํ๋ค.
์ด์ค ํด์ฑ (Double Hashing):
- ๋ ๋ฒ์งธ ํด์ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ๋จ๊ณ ๊ณ์ฐ:
index = (index + i * hash2(key)) % size
. - ํด๋ฌ์คํฐ๋ง ๋ฌธ์ ๊ฐ ์ ์ง๋ง ๊ตฌํ์ด ๋ณต์กํ๋ค.
์คํ ์ด๋๋ ์ฑ ๋ฐฉ๋ฒ ๊ตฌํ ์์ (์ ํ ํ์ฌ): ์ ์ฒด ์๋ ์ฝ๋๋ฅผ ์ ๊ณตํ ํ ๋ insert ํจ์์ ์๋ ๋ฐฉ์๋ง ํ์ ํด๋ ๋ผ
class HashTableOpenAddressing:
def __init__(self, size):
self.size = size
self.table = [None] * size
def hash_function(self, key):
return hash(key) % self.size
def insert(self, key, value):
index = self.hash_function(key)
original_index = index
while self.table[index] is not None:
if self.table[index][0] == key:
self.table[index] = (key, value)
return
index = (index + 1) % self.size
if index == original_index:
raise Exception("Hash table is full")
self.table[index] = (key, value)
def search(self, key):
index = self.hash_function(key)
original_index = index
while self.table[index] is not None:
if self.table[index][0] == key:
return self.table[index][1]
index = (index + 1) % self.size
if index == original_index:
break
return None
def delete(self, key):
index = self.hash_function(key)
original_index = index
while self.table[index] is not None:
if self.table[index][0] == key:
self.table[index] = None
return
index = (index + 1) % self.size
if index == original_index:
break
# ์ฌ์ฉ ์์ :
hash_table = HashTableOpenAddressing(10)
hash_table.insert("apple", 1)
hash_table.insert("banana", 2)
hash_table.insert("cherry", 3)
print(hash_table.search("banana")) # ์ถ๋ ฅ: 2
hash_table.delete("banana")
print(hash_table.search("banana")) # ์ถ๋ ฅ: None
7.4 ์ถฉ๋์ด ํด์ ํ ์ด๋ธ์ ๋ฏธ์น๋ ์ํฅ
์ถฉ๋์ด ์ฑ๋ฅ์ ๋ฏธ์น๋ ์ํฅ.
ํ๊ท ์ ๊ทผ ์๊ฐ:
- ์ด์์ ์ธ ์กฐ๊ฑด(์ถฉ๋์ด ์๋ ๊ฒฝ์ฐ)์์ ํด์ ํ
์ด๋ธ์ ์์์ ๋ํ ํ๊ท ์ ๊ทผ ์๊ฐ์
O(1)
์ด๋ค. - ์ถฉ๋์ด ๋ฐ์ํ ๊ฒฝ์ฐ, ์ฒด์ธ์ ๊ด๋ฆฌํ๊ฑฐ๋ ์ ์ ํ์ฌํด์ผ ํ๋ฏ๋ก ์ ๊ทผ ์๊ฐ์ด ์ฆ๊ฐํด.
์ฒด์ธ์ ๊ธธ์ด ์ฆ๊ฐ:
- ์ฒด์ด๋ ๋ฐฉ๋ฒ์์ ์ถฉ๋์ด ๋ง์ ๊ฒฝ์ฐ ์ฒด์ธ์ ๊ธธ์ด๊ฐ ์ฆ๊ฐํ๋ฉด ๊ฒ์, ์ฝ์
๋ฐ ์ญ์ ์ฐ์ฐ์ ๋ํ ์ ๊ทผ ์๊ฐ์ด
O(n)
์ด ๋ ์ ์์ด. - ๊ธด ์ฒด์ธ์ ์์๋ฅผ ์ฐพ๊ฑฐ๋ ์ฝ์ ํ ๋ ํ์ํ ๋น๊ต ํ์๋ฅผ ์ฆ๊ฐ์ํจ๋ค.
๊ณต๊ฐ ๋ณต์ก์ฑ:
- ์ฒด์ด๋ ๋ฐฉ๋ฒ์์๋ ์ฐ๊ฒฐ ๋ฆฌ์คํธ์ ํฌ์ธํฐ๋ฅผ ์ ์ฅํ๊ธฐ ์ํ ์ถ๊ฐ ๋ฉ๋ชจ๋ฆฌ๊ฐ ํ์ํด.
- ์คํ ์ด๋๋ ์ฑ ๋ฐฉ๋ฒ์์๋ ํ ์ด๋ธ ๋ฐ๋๊ฐ ์ผ์ ์์ค(์ผ๋ฐ์ ์ผ๋ก ์ฝ 70-80%) ์ด์์ด ๋ ๋ ์ถฉ๋์ด ํฌ๊ฒ ์ฆ๊ฐํ๊ณ ์ด์ ๋ฐ๋ผ ์ ๊ทผ ์๊ฐ์ด ๋์ด๋๋ค.
ํด๋ฌ์คํฐ๋ง: ์คํ ์ด๋๋ ์ฑ ๋ฐฉ๋ฒ(ํนํ ์ ํ ํ์ฌ)์ ์ฌ์ฉํ ๋ ์ฌ๋ฌ ์ฐ์๋ ์ ๋ค์ด ์ฐจ์ง๋๋ ํด๋ฌ์คํฐ๋ง ํ์์ด ๋ฐ์ํ์ฌ ์ถฉ๋ ๊ฐ๋ฅ์ฑ์ด ์ฆ๊ฐํ๊ณ ์ฑ๋ฅ์ด ์ ํ๋๋ค.
์ถฉ๋์ด ์ฑ๋ฅ์ ๋ฏธ์น๋ ์ํฅ ๋ถ์ ์์ :
๊น์ด ํ๊ณ ๋ค๊ณ ์ถ์ดํ๋ ์ฌ๋๋ค์ ์ํ ๊ฒ
import time
import random
# ์ ํ ํ์ฌ
class HashTableOpenAddressing:
def __init__(self, size):
self.size = size
self.table = [None] * size
def hash_function(self, key):
return hash(key) % self.size
def insert(self, key, value):
index = self.hash_function(key)
original_index = index
while self.table[index] is not None:
if self.table[index][0] == key:
self.table[index] = (key, value)
return
index = (index + 1) % self.size
if index == original_index:
raise Exception("Hash table is full")
self.table[index] = (key, value)
def search(self, key):
index = self.hash_function(key)
original_index = index
while self.table[index] is not None:
if self.table[index][0] == key:
return self.table[index][1]
index = (index + 1) % self.size
if index == original_index:
break
return None
# ์ฝ์
ํ ๋ฐ์ดํฐ ๋ง์ด ์์ฑํ๊ธฐ
hash_table = HashTableOpenAddressing(1000)
keys = [random.randint(1, 10000) for _ in range(800)]
# ๋ฐ์ดํฐ ์ฝ์
๋ฐ ์๊ฐ ์ธก์
start_time = time.time()
for key in keys:
hash_table.insert(key, key)
print(f"์ฝ์
์๊ฐ: {time.time() - start_time:.6f} ์ด")
# ๋ฐ์ดํฐ ๊ฒ์ ๋ฐ ์๊ฐ ์ธก์
start_time = time.time()
for key in keys:
hash_table.search(key)
print(f"๊ฒ์ ์๊ฐ: {time.time() - start_time:.6f} ์ด")
GO TO FULL VERSION