Skip to content

Is for loop still good#

Question: O(n) vs O(1)#

  • We all know that accessing a hashmap element costs O(1) of time and finding an element inside an array costs O(n) of time.
  • But
    • O(1) is the hashing function cost
    • O(n) is the number of elements
  • How large of an array must be, that the finding loop cost exceeds the cost of the hashing function?

Benchmark in Golang#

go test -bench=. -benchmem
goos: linux
goarch: amd64
pkg: github.com/thanhpp/gopher/bench-hashmap
cpu: AMD Ryzen 5 5600G with Radeon Graphics
BenchmarkSliceInt/size_1-12             125404327                9.605 ns/op           0 B/op          0 allocs/op
BenchmarkSliceInt/size_5-12             69207064                17.54 ns/op            0 B/op          0 allocs/op
BenchmarkSliceInt/size_10-12            63447366                18.60 ns/op            0 B/op          0 allocs/op
BenchmarkSliceInt/size_20-12            58960952                20.43 ns/op            0 B/op          0 allocs/op
BenchmarkSliceInt/size_30-12            54392230                21.73 ns/op            0 B/op          0 allocs/op
BenchmarkSliceInt/size_40-12            53013524                23.26 ns/op            0 B/op          0 allocs/op
BenchmarkSliceInt/size_50-12            49305501                24.35 ns/op            0 B/op          0 allocs/op

BenchmarkMapInt/size_1-12               106518439               11.28 ns/op            0 B/op          0 allocs/op
BenchmarkMapInt/size_5-12               67979809                18.07 ns/op            0 B/op          0 allocs/op
BenchmarkMapInt/size_10-12              47070580                26.61 ns/op            0 B/op          0 allocs/op
BenchmarkMapInt/size_20-12              45591961                26.35 ns/op            0 B/op          0 allocs/op
BenchmarkMapInt/size_30-12              44955747                27.24 ns/op            0 B/op          0 allocs/op
BenchmarkMapInt/size_40-12              46008104                25.74 ns/op            0 B/op          0 allocs/op
BenchmarkMapInt/size_50-12              42991318                27.75 ns/op            0 B/op          0 allocs/op

BenchmarkSliceString/size_1-12          94805643                12.54 ns/op            0 B/op          0 allocs/op
BenchmarkSliceString/size_5-12          53173370                22.47 ns/op            0 B/op          0 allocs/op
BenchmarkSliceString/size_10-12         42057357                28.63 ns/op            0 B/op          0 allocs/op
BenchmarkSliceString/size_20-12         34653843                34.05 ns/op            0 B/op          0 allocs/op
BenchmarkSliceString/size_30-12         28817215                41.65 ns/op            0 B/op          0 allocs/op
BenchmarkSliceString/size_40-12         23304921                52.29 ns/op            0 B/op          0 allocs/op
BenchmarkSliceString/size_50-12         19114158                62.58 ns/op            0 B/op          0 allocs/op

BenchmarkMapString/size_1-12            93007335                13.08 ns/op            0 B/op          0 allocs/op
BenchmarkMapString/size_5-12            52409577                23.35 ns/op            0 B/op          0 allocs/op
BenchmarkMapString/size_10-12           42127460                26.81 ns/op            0 B/op          0 allocs/op
BenchmarkMapString/size_20-12           39925528                30.12 ns/op            0 B/op          0 allocs/op
BenchmarkMapString/size_30-12           43890310                27.75 ns/op            0 B/op          0 allocs/op
BenchmarkMapString/size_40-12           39024145                31.18 ns/op            0 B/op          0 allocs/op
BenchmarkMapString/size_50-12           37039489                32.53 ns/op            0 B/op          0 allocs/op
PASS
ok      github.com/thanhpp/gopher/bench-hashmap 45.370s
  • Analytic:
    • The slice loop cost increases with the size of the slice (of course ^^).
    • When the sizes are small enough (1, 5, 10): the cost of searching in a slice is cheaper.
    • The cost of accessing a map in Golang is not a constant
      • When the size reaches a threshold, the cost increases significantly. (1 -> 5/10)
      • https://github.com/golang/go/blob/master/src/runtime/map.go
    • With different types
      • For slices, searching for integers is faster than searching for strings (which might be caused by the compare cost).
      • For maps, searching for both types shows similar results.