[Go] Map ์›๋ฆฌ์™€ ํ™œ์šฉ(feat. hash)

2025. 11. 5. 18:01ยทํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด/Go

์†Œ๊ฐœ

Go์˜ map์€ ๋งค์šฐ ์ค‘์š”ํ•œ ๋‚ด์žฅ ์ž๋ฃŒ๊ตฌ์กฐ๋กœ, key-value ํ˜•ํƒœ์˜ ํ•ด์‹œ ํ…Œ์ด๋ธ”(hash table) ๊ธฐ๋ฐ˜ ์ปจํ…Œ์ด๋„ˆ์ž…๋‹ˆ๋‹ค.

์›๋ฆฌ (๋‚ด๋ถ€ ๊ตฌ์กฐ)

Go์˜ map์€ hash table์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ตฌํ˜„๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•ต์‹ฌ ๊ฐœ๋…

  • Key → Hashing → Bucket → Value
  • ํ•ด์‹œ ํ•จ์ˆ˜(hash(key))๋ฅผ ํ†ตํ•ด ๋ฒ„ํ‚ท(bucket) ์ธ๋ฑ์Šค๋ฅผ ๊ณ„์‚ฐํ•˜๊ณ , ๊ทธ ๋ฒ„ํ‚ท์— key-value ์Œ์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
  • ํ•ด์‹œ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•˜๋ฉด ๊ฐ™์€ ๋ฒ„ํ‚ท ์•ˆ์˜ ์Šฌ๋กฏ์— ์ฒด์ด๋‹(chaining) ํ˜•ํƒœ๋กœ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

๋‚ด๋ถ€ ๊ตฌ์กฐ ๊ฐœ์š”

Go ๋Ÿฐํƒ€์ž„์—์„œ map์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ตฌ์กฐ๋กœ ๊ด€๋ฆฌ๋ฉ๋‹ˆ๋‹ค (runtime/map.go ์ฐธ๊ณ ):

type hmap struct {
    count     int           // ์š”์†Œ ๊ฐœ์ˆ˜
    flags     uint8
    B         uint8         // ๋ฒ„ํ‚ท ์ˆ˜ = 2^B
    buckets   unsafe.Pointer // ์‹ค์ œ ๋ฐ์ดํ„ฐ ์ €์žฅ์†Œ
    oldbuckets unsafe.Pointer // ๋ฆฌ์‚ฌ์ด์ง• ์ค‘์ธ ๋ฒ„ํ‚ท
    ...
}
  • ๋ฒ„ํ‚ท ์ˆ˜(bucket count): 2^B
  • ๋ฆฌ์‚ฌ์ด์ง•(resize): ์š”์†Œ๊ฐ€ ๋งŽ์•„์ง€๋ฉด ์ž๋™์œผ๋กœ ๋ฒ„ํ‚ท ํฌ๊ธฐ๊ฐ€ 2๋ฐฐ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.
  • Load factor (ํ‰๊ท  ๋ฒ„ํ‚ท๋‹น ์›์†Œ ์ˆ˜)๊ฐ€ ์ผ์ • ๊ธฐ์ค€ ์ด์ƒ์ด๋ฉด ์žฌ๋ฐฐ์—ด(rehashing) ์ˆ˜ํ–‰.

์‚ฌ์šฉ๋ฒ•

๊ธฐ๋ณธ ์„ ์–ธ ๋ฐ ์ดˆ๊ธฐํ™”

// ๋นˆ ๋งต ์„ ์–ธ
var m map[string]int  // nil ์ƒํƒœ, ๋ฐ”๋กœ ์‚ฌ์šฉ ๋ถˆ๊ฐ€

// make๋ฅผ ์‚ฌ์šฉํ•œ ์ดˆ๊ธฐํ™”
m = make(map[string]int)

// ๋˜๋Š” ํ•œ ์ค„ ์ดˆ๊ธฐํ™”
m := map[string]int{
    "apple":  3,
    "banana": 5,
}

์‚ฝ์ž… (Insert / Update)

m["apple"] = 10  // ์ถ”๊ฐ€ ๋˜๋Š” ์ˆ˜์ •

์กฐํšŒ (Lookup)

val := m["apple"]     // ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด 0 (int์˜ zero value)
val, ok := m["apple"] // ok == true์ด๋ฉด ์กด์žฌ

์‚ญ์ œ (Delete)

delete(m, "apple")

์ˆœํšŒ (Iteration)

for key, value := range m {
    fmt.Println(key, value)
}

Go์˜ map์€ iteration ์ˆœ์„œ๊ฐ€ ๋งค๋ฒˆ ๋žœ๋ค(randomized) ์ž…๋‹ˆ๋‹ค. ๋ณด์•ˆ์„ฑ๊ณผ ํ•ด์‹œ ๊ณต๊ฒฉ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด ์„ค๊ณ„์ƒ ์ˆœ์„œ๊ฐ€ ๋ณด์žฅ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

 

์„ฑ๋Šฅ ๋ฐ ๋™์ž‘ ํŠน์„ฑ

์žฅ์ 

  • ํ‰๊ท  ์ ‘๊ทผ ์‹œ๊ฐ„ O(1)
  • ํ•ด์‹œ ๊ธฐ๋ฐ˜์ด๋ผ ๋น ๋ฅด๊ณ  ํšจ์œจ์ 
  • ํ‚ค ํƒ€์ž…์œผ๋กœ comparableํ•œ ํƒ€์ž… ์‚ฌ์šฉ ๊ฐ€๋Šฅ (== ๋น„๊ต ๊ฐ€๋Šฅํ•œ ํƒ€์ž…)

์ฃผ์˜์‚ฌํ•ญ

  1. Concurrent access ๊ธˆ์ง€
    • ์—ฌ๋Ÿฌ ๊ณ ๋ฃจํ‹ด์ด ๋™์‹œ์— ์ฝ๊ธฐ/์“ฐ๊ธฐ ํ•˜๋ฉด fatal error: concurrent map read and map write
    • ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•: sync.Mutex ๋˜๋Š” sync.RWMutex๋กœ ๋ณดํ˜ธํ•˜๊ฑฐ๋‚˜, sync.Map ์‚ฌ์šฉ
    var mu sync.RWMutex
    mu.Lock()
    m["x"] = 1
    mu.Unlock()
  2. Nil map ์ฃผ์˜
  3. var m map[string]int m["a"] = 1 // panic! (nil map์— ํ• ๋‹น ๋ถˆ๊ฐ€)
  4. ์ˆœ์„œ ๋ณด์žฅ X
    • ์ถœ๋ ฅ ์ˆœ์„œ๊ฐ€ ๋งค๋ฒˆ ๋‹ค๋ฆ„ → ์ˆœ์„œ๋ฅผ ์›ํ•œ๋‹ค๋ฉด slice๋กœ key๋ฅผ ์ •๋ ฌํ•ด์•ผ ํ•จ.

์˜ˆ์ œ: ๋นˆ๋„ ์นด์šดํŠธ

func main() {
    words := []string{"apple", "banana", "apple", "orange", "banana"}
    freq := make(map[string]int)

    for _, w := range words {
        freq[w]++ // ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด 0์—์„œ ์‹œ์ž‘
    }

    for k, v := range freq {
        fmt.Printf("%s: %d\\n", k, v)
    }
}

๊ด€๋ จ ๊ฐœ๋… ์ถ”์ฒœ

  • sync.Map: concurrent-safe map (lock-free, atomic ์ ‘๊ทผ ์ง€์›)
  • map[string]interface{}: JSON ํŒŒ์‹ฑ ์‹œ ์ž์ฃผ ์‚ฌ์šฉ
  • struct{}: value๋ฅผ ๋นˆ ๊ตฌ์กฐ์ฒด๋กœ ๋‘์–ด set์ฒ˜๋Ÿผ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
set := make(map[string]struct{}) 
set["A"] = struct{}{} 
if _, ok := set["A"]; ok { fmt.Println("exists") }

Go์˜ map์€ ํ•ด์‹œ ๊ธฐ๋ฐ˜์˜ ํ‚ค-๊ฐ’ ์ž๋ฃŒ๊ตฌ์กฐ๋กœ, ํ‰๊ท  ์ ‘๊ทผ ์‹œ๊ฐ„์€ O(1), ๋‚ด๋ถ€์ ์œผ๋กœ ๋ฒ„ํ‚ท ๋ฆฌ์‚ฌ์ด์ง•๊ณผ ํ•ด์‹œ ๋ถ„์‚ฐ์„ ํ†ตํ•ด ์•ˆ์ •์ ์ธ ์„ฑ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋งŒ, ๋™์‹œ์„ฑ ์ œ์–ด์™€ ์ˆœ์„œ ๋น„๋ณด์žฅ์€ ๋ฐ˜๋“œ์‹œ ์ฃผ์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ €์ž‘์žํ‘œ์‹œ (์ƒˆ์ฐฝ์—ด๋ฆผ)

'ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด > Go' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[Go] ์ผ์ • ์‹œ๊ฐ„๋งˆ๋‹ค ์Šค์ผ€์ค„๋Ÿฌ ๋™์ž‘ํ•˜๊ธฐ(Ticker)  (0) 2025.11.07
[Go] ํ˜•์‹์ง€์ •์ž Format ์ •๋ฆฌ(%v,%s,%d ๋“ฑ)  (0) 2025.11.07
[Go] ์Šฌ๋ผ์ด์Šค(slice)์—๋Š” ํฌ์ธํ„ฐ๊ฐ€ ์žˆ๋‹ค  (0) 2025.10.14
[Go] ๊ณ ๋ฃจํ‹ด(Goroutine)  (0) 2025.10.13
[Go] Gin ํ”„๋ ˆ์ž„์›Œํฌ  (1) 2025.09.20
'ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด/Go' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • [Go] ์ผ์ • ์‹œ๊ฐ„๋งˆ๋‹ค ์Šค์ผ€์ค„๋Ÿฌ ๋™์ž‘ํ•˜๊ธฐ(Ticker)
  • [Go] ํ˜•์‹์ง€์ •์ž Format ์ •๋ฆฌ(%v,%s,%d ๋“ฑ)
  • [Go] ์Šฌ๋ผ์ด์Šค(slice)์—๋Š” ํฌ์ธํ„ฐ๊ฐ€ ์žˆ๋‹ค
  • [Go] ๊ณ ๋ฃจํ‹ด(Goroutine)
์„œ์•„๋ž‘๐Ÿ˜ƒ
์„œ์•„๋ž‘๐Ÿ˜ƒ
Just Do It๐Ÿ’ช
  • ์„œ์•„๋ž‘๐Ÿ˜ƒ
    G-Stack
    ์„œ์•„๋ž‘๐Ÿ˜ƒ
  • ์ „์ฒด
    ์˜ค๋Š˜
    ์–ด์ œ
    • ์ „์ฒด๋ณด๊ธฐ (144)
      • ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด (78)
        • C++ ๊ธฐ์ดˆ (28)
        • C++ ์‘์šฉ (18)
        • Python (18)
        • JavaScript & NodeJS (0)
        • Go (12)
        • React & NextJS (2)
        • Java (0)
      • AI (2)
      • ์ปดํ“จํ„ฐ ๊ตฌ์กฐ & ์šด์˜์ฒด์ œ (31)
      • ์•Œ๊ณ ๋ฆฌ์ฆ˜ (12)
      • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค (5)
      • ๋„คํŠธ์›Œํฌ (3)
      • ๋””์ž์ธํŒจํ„ด (5)
      • ์„œ๋น„์Šค & ํˆด (7)
      • ํŠธ๋ Œ๋“œ&์ด์Šˆ (1)
  • ๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

    • ํ™ˆ
    • ํƒœ๊ทธ
    • ๋ฐฉ๋ช…๋ก
  • ๋งํฌ

  • ๊ณต์ง€์‚ฌํ•ญ

    • G์Šคํƒ์˜ ๊ธฐ์ˆ  ๋ธ”๋กœ๊ทธ
  • ์ธ๊ธฐ ๊ธ€

  • ํƒœ๊ทธ

    ์กฐ๊ฑด๋ฌธ
    ๋ณ€์ˆ˜
    ์ƒ์†
    ์ปดํ“จํ„ฐ
    component
    ๋ฐฐ์—ด
    ํŒŒ์ด์ฌ
    go
    pointer
    init
    ํŒจํ‚ค์ง€
    ์Šคํƒ
    ํŒŒ์ผ์ž…์ถœ๋ ฅ
    ๋ฉ”๋ชจ๋ฆฌ
    ์žฌ๊ท€
    Thread
    ๋””์ž์ธํŒจํ„ด
    STD
    ํ•˜๋“œ๋””์Šคํฌ
    ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค
    RAM
    c++
    ํฌ์ธํ„ฐ
    fork
    ๊ฐ€์ƒ๋ฉ”๋ชจ๋ฆฌ
    ๋ฐ˜๋ณต๋ฌธ
    ํ•จ์ˆ˜
    c
    ์•Œ๊ณ ๋ฆฌ์ฆ˜
    cpu
  • ์ตœ๊ทผ ๋Œ“๊ธ€

  • ์ตœ๊ทผ ๊ธ€

  • hELLOยท Designed By์ •์ƒ์šฐ.v4.10.6
์„œ์•„๋ž‘๐Ÿ˜ƒ
[Go] Map ์›๋ฆฌ์™€ ํ™œ์šฉ(feat. hash)
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”