
위와 같이 키와 값이 들어있는 경우, 해시 테이블에 저장하는 방법은 어떻게 될까?
해시 함수가 키의 아스키코드를 테이블 크기인 3으로 나눈 나머지를 구한다고 가정해보자
a의 데이터를 저장할 때, hash_function("a")(=ASCII 97) % 3(테이블 크기) 을 통해서 index 값인 1을 구해내고, array[1] = "apple"을 저장함
각 키의 해시 값을 계산하면 다음과 같다.
“a” → 해시 함수(97 % 3) → 1
“b” → 해시 함수(98 % 3) → 2
“c” → 해시 함수(99 % 3) → 0
이런 형식으로 데이터를 저장하면, key에 대한 데이터를 찾을 때, hash_function을 한번만 수행하면 array 내에 저장된 index 위치를 찾아낼 수 있기 때문에 데이터의 저장과 삭제가 매우 빠름
따라서, 해시 테이블은 검색, 저장, 삭제를 자주 하거나, 중복 확인 및 개수를 셀 때 사용하면 편하며, 관계를 표현할 때도 유용함
해시 테이블의 기본 연산은 삽입, 삭제 및 탐색!
충돌이 발생하지 않는다고 가정한다면, 시간 복잡도는 다음과 같음
따라서 FullScan과 같은 선형탐색보다(=O(N)) 훨씬 빠르게 자료값을 찾는다고 볼 수 있음!
| operation | Dictionary | List |
|---|---|---|
| Get Item | O(1) | O(1) |
| Insert Item | O(1) | O(1) |
| Update Item | O(1) | O(1) ~ O(N) |
| Delete Item | O(1) | O(1) |
| Search Item | O(1) | O(1) ~ O(N) |
딕셔너리의 시간 복잡도는 대부분 O(1)이며, 원소를 넣거나 삭제, 찾는 일이 많을 때에는 딕셔너리를 사용하는 것이 좋음! (* 파이썬 3.7 이상부터 딕셔너리는 원소의 들어온 순서 보장, 3.7 미만은 유의)
# 1. 빈 딕셔너리 생성
empty_dict1 = {}
empty_dict2 = dict()
# 2. 초기값이 있는 딕셔너리 생성
# key-value 쌍으로 데이터를 저장
person = {
'name': '나나',
'weight': 44,
'height': 157,
}
# {'height': 157, 'name': '나나', 'weight': 44}
# 3. 중첩된 딕셔너리 생성
# 딕셔너리를 값으로 가지는 중첩된 딕셔너리도 만들 수 있음
animals = {
'Dog': {
'name': '보리',
'age': 6
},
'Cat': {
'name': '나비',
'weight': 4
}
}
# { 'Dog': { 'name': '보리', 'age': 6},
# 'Cat': {'name': '나비','weight': 4 }}
# 4. `fromkeys()` 메소드 사용
# 동일한 기본값으로 초기화된 딕셔너리 생성
keys = ['a', 'b', 'c']
default_dict = dict.fromkeys(keys, 0)
print(default_dict) # {'a': 0, 'b': 0, 'c': 0}
# 값 생략 시 기본값은 `None`
none_dict = dict.fromkeys(keys)
print(none_dict) # {'a': None, 'b': None, 'c': None}
# 1. 대괄호 `[]` 사용
# 해당 키가 존재하지 않으면 `KeyError`가 발생
person = {'가나다라': 300, '마바사': 180}
print(person['가나다라']) # 300
# 2. `get()` 메소드 사용
# 키가 없으면 기본값을 반환하도록 설정할 수 있음
print(person.get('보리', 0)) # 0
# 1. 값 추가
# 딕셔너리에 새로운 키-값 쌍을 추가할 수 있음
scores = {'루이': 300, '미나': 180}
scores['재하'] = 100
# 2. 값 수정
# 기존 값 수정은 대괄호를 사용해 간단히 할 수 있음
scores['루이'] = 500 # 특정 값으로 변경
scores['루이'] += 300 # 기존 값에 더하기
# 1. `del` 키워드 사용
# 키가 존재하지 않으면 `KeyError`가 발생
del scores['루이']
# 2. `pop()` 메소드 사용
# 키가 없으면 기본값을 반환하도록 설정할 수 있음
value = scores.pop('수진', 0) # 0
print(value)
# 1. 키만 순회
for key in scores:
print(key)
# 2. 키와 값 동시에 순회
for key, value in scores.items():
print(f"{key}: {value}")
# 1. 키 존재 여부 확인
# `in` 키워드를 사용하면 특정 키의 존재 여부를 확인할 수 있음
print('미나' in scores) # True
print('미나' not in scores) # False
# 2. 키, 값 추출
# `keys()`: 키 목록 반환
# `values()`: 값 목록 반환
# `items()`: 키-값 쌍 반환
print(scores.keys()) # dict_keys(['미나'])
print(scores.values()) # dict_values([180])
print(scores.items()) # dict_items([('미나', 180)])
# 특정 키 존재 여부 확인 예제
students = {'지민': 17, '태희': 15, '윤아': 18}
if '지민' in students:
print('지민 is in students')
else:
print('지민 is not in students')
# 키, 값 순회 예제
for student, age in students.items():
print(f"{student}: {age}")
# 값 삭제 및 초기화 예제
del students['지민']
print(students) # {'태희': 15, '윤아': 18}
students.clear()
print(students) # {}
리스트 사용이 불가할 경우
빠른 접근 및 탐색이 필요할 경우
집계가 필요할 경우
(1) Hash(해시)
(2) 해시(Hash)란 무엇인가(feat. Dictionary 자료구조)
(3) 파이썬으로 해시 테이블 구현하기