Array와 Map의 쓰임은 명백히 다르다.
하지만 key가 정수일 경우, Map 대신 Array를 사용할 수 있다.
Array는 별도의 과정(hash 값 계산, hash 충돌 처리, hash Table 확장)없이 값을 저장/조회할 수 있기 때문에 더 빠를 것이다.
정말 Map 대신 Array를 사용하는 것이 빠른지 확인해보자
단순히 주어진 반복 횟수 repeat
만큼 값을 저장하는 코드를 작성하였다.
Array와 HashMap 각각 몇초가 걸리는 지 확인해보자.
import kotlin.system.measureNanoTime
fun arrayTime(repeat: Int): Double {
val value = "value"
val a = Array<String>(repeat) { value }
return measureNanoTime {
for (j in 0 until repeat) {
a[j] = value
}
} / 1000000000.0
}
fun mapTime(repeat: Int): Double {
val a = hashMapOf<Int, String>()
val value = "value"
return measureNanoTime {
for (j in 0 until repeat) {
a[j] = value
}
} / 1000000000.0
}
fun main() {
println("repeat 100만회, array: ${arrayTime(1000000)}, map: ${mapTime(1000000)}")
println("repeat 1000만회, array: ${arrayTime(10000000)}, map: ${mapTime(10000000)}")
println("repeat 2000만회, array: ${arrayTime(20000000)}, map: ${mapTime(20000000)}")
println("repeat 3000만회, array: ${arrayTime(30000000)}, map: ${mapTime(30000000)}")
println("repeat 4000만회, array: ${arrayTime(40000000)}, map: ${mapTime(40000000)}")
println("repeat 5000만회, array: ${arrayTime(50000000)}, map: ${mapTime(50000000)}")
println("repeat 6000만회, array: ${arrayTime(60000000)}, map: ${mapTime(60000000)}")
println("repeat 7000만회, array: ${arrayTime(70000000)}, map: ${mapTime(70000000)}")
}
//출력
repeat 100만회, array: 0.012976, map: 0.1315592
repeat 1000만회, array: 0.1056955, map: 1.2990614
repeat 2000만회, array: 0.2796117, map: 1.8312339
repeat 3000만회, array: 0.307373, map: 2.7570212
repeat 4000만회, array: 0.4013876, map: 4.2946401
repeat 5000만회, array: 0.6792158, map: 5.4680324
repeat 6000만회, array: 0.8924631, map: 8.086752
repeat 7000만회, array: 0.7252884, map: 11.2050608
⇒ Array의 경우 횟수에 무관해 보일 만큼 소요시간의 차이가 없고 매우 빠르다.
⇒ HashMap의 경우 대략 1000만회당 1초가 소요된다.
hashMap의 저장/접근의 시간복잡도는 O(1)로 Array와 동일하다.
그렇다면 왜 결과가 더 느리게 나온걸까..?
hashMap이 저장/접근이 O(1)이라고 하는 이유는 key를 hash값으로 바꾸는 과정이 단순 연산이기 때문이다. 하지만 이는 hash 충돌과 load factor에 따른 확장을 고려하지 않은 수치이다.
실제론 숨겨진 두개의 과정이 더 발생한다.