Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- designPattern
- 옵저버 패턴
- factory method
- Observer Pattern
- Kotlin
- 추상 팩토리
- 디자인패턴 #
- r
- 프로토타입 패턴
- a
- Functional Programming
- PrototypePattern
- builderPattern
- Design Pattern
- 추상팩토리패턴
- 싱글톤
- 디자인패턴
- 팩토리 메소드
- Singleton
- El
- ㅓ
- 함수형프로그래밍
- 빌터패턴
- 코틀린
- Abstract Factory
- F
- ㅋㅁ
Archives
- Today
- Total
오늘도 더 나은 코드를 작성하였습니까?
Hash Collision(해시 충돌) Chaining(체이닝) 및 kotlin 구현 본문
해시 충돌
hash function이 서로 다른 두 개의 입력값에 대해 동일한 출력값을 내는 상황
Chainning (체이닝)
hashTable의 각 슬롯이 연결 리스트의 형태로 데이터를 저장하여, 동일한 출력을 값을 가지는 데이터가 들어 오더라도 같은 hash table의Idx에 저장하여 충돌을 해결한다.
새로운 데이터를 넣을때는 각 해당 슬롯의 가장 앞에 삽입한다. 그러면 항상 O(1)의 시간이 걸린다.
하지만, 검색 및 삭제는 해당 슬롯의 충돌되어 삽입된 갯수에 따라 성능이 좌우된다.
이때, hashFunction을 C-Universal Function을 사용하면, 각 슬롯의 평균적인 연결리스트의 길이는 O(1)이라 이미 증명되어 있다.
class ChainingHashTable<K, V>(private var initTableSize: Int = DEFAULT_TABLE_SIZE) {
companion object {
private const val DEFAULT_TABLE_SIZE = 20
}
private var size = 0
private var table: Array<Node<K, V>?> = Array(initTableSize) { null }
private class Node<K, V>(val key: K, var value: V, var next: Node<K, V>? = null) {
val hashCode = key.hashCode()
override fun toString(): String {
return "(key: $key value: $value)"
}
}
constructor(vararg args: Pair<K, V>) : this(if (args.size > DEFAULT_TABLE_SIZE) args.size else DEFAULT_TABLE_SIZE) {
val tableSize = if (args.size > DEFAULT_TABLE_SIZE) args.size else DEFAULT_TABLE_SIZE
table = Array(tableSize) { null }
args.forEach {
put(it.first, it.second)
}
}
/*
key를 입력받아 현재 hashTable 해당하는 key값을 가진 Node가 있는지 확인합니다.
있다면 node를 반환하고 없으면 null을 반환 합니다.
*/
private fun findNode(key: K): Node<K, V>? {
val idx = hashValue(key)
var p = table[idx]
while (p != null) {
if (p.key == key)
return p
p = p.next
}
return p
}
/*
<key, Value> 데이터를 입력받아서,
기존에 있던 Key면 데이터를 업데이트 합니다, 없다면 새로운 데이터를 해당 idx의 Chain 가장 앞에 삽입 합니다.
*/
fun put(key: K, value: V): K {
val node = findNode(key)
if (node != null && node.key == key) {
// 값을 업데이트
node.value = value
} else {
// 새로운 노드 삽입.
table[hashValue(key)] = Node(key, value, table[hashValue(key)])
size += 1
}
return key
}
/*
key 값에 대응 하는 value를 리턴한다.
*/
fun search(key: K): V? {
val idx = hashValue(key)
var p = table[idx]
while (p != null) {
if (p.key == key)
return p.value
p = p.next
}
return null
}
/*
해당 key가 table에 존재한다면, key 값에 대응 하는 value를 삭제하고 key 반환.
key가 table에 없다면, 무시한다.
*/
fun delete(key: K) {
val node = findNode(key) ?: return
// 삭제할 노드의 앞선 노드를 찾는다.
var prev = table[hashValue(key)]!!
// 삭제할 노드가 체인의 가장 앞쪽 이라면,
if (prev.key == node.key){
table[hashValue(key)] = null
}else{
while (prev.next?.key != node.key){
val next = prev.next ?: return
prev = next
}
prev.next = node.next
size -= 1
}
}
fun hashValue(key: K) = key.hashCode() % table.size
override fun toString(): String {
val sb = StringBuilder()
table.forEachIndexed { idx, chain ->
sb.append("idx: $idx ")
var node = chain
while (node != null) {
sb.append(node.toString())
node = node.next
}
sb.append("\n")
}
return sb.toString()
}
}
'자료구조' 카테고리의 다른 글
Stack(스택) feat.kotlin (1) | 2023.11.23 |
---|---|
Heap의 정의와 kotlin 구현 (1) | 2023.11.18 |
HashTable Open Addressing(Linear Probing) kotlin 구현 (0) | 2023.11.10 |
Hash Collision(해시 충돌) Open Addressing(개방 주소법) (1) | 2023.11.09 |
Map Hash(Hash Table, Hash Function) (1) | 2023.11.07 |