container package
golang에는 빌트인으로 사용할 수 있는 container package가 있다.
개발을 하다보면, 자료구조를 사용할 일이 꽤 생긴다.
go에서는 container 패키지에서 기본 자료구조를 제공해주므로 꽤나 편리하게 사용할 수 있다.
패키지에서 제공하는 자료구조는 다음과 같다.
container 패키지를 이용해서 간단한 자료구조를 구현해보자.
container/list
Copy package main
import (
"container/list"
"log"
)
func main () {
lst := list.New()
lst.PushBack( 1 )
lst.PushBack( 2 )
lst.PushBack( 3 )
log.Println(lst.Len())
}
위와 같이 container/list
패키지를 import하면, 손쉽게 linked list를 사용할 수 있다.
개발을 하면서 linked list를 사용해야 한다면, 꽤나 시간을 단축시킬 수 있을 것이다.
list를 순회하고 싶다면 아래와 같은 방법도 가능하다.
Copy package main
import (
"container/list"
"fmt"
"log"
)
func main () {
lst := list.New()
lst.PushBack( 1 )
lst.PushBack( 2 )
lst.PushBack( 3 )
log.Println(lst.Len())
for e := lst.Front(); e != nil ; e = e.Next() { // 연결 리스트의 맨 앞부터 끝까지 순회
fmt.Println(e.Value)
}
}
container/heap
다음은 heap 패키지이다. 필자는 최근 회사에서 체결엔진/오더북을 구현하면서 min heap과 max heap을 구현할 일이 있었는데,
container/heap 패키지를 통해 간단하게 구현할 수 있었다.
heap 패키지에서는 기본적으로 다음과 같은 인터페이스가 필요하다.
Copy package heap
type Interface interface {
Len () int
Less (i, j int ) bool
Swap (i, j int )
Push (x any )
Pop () any
}
한 번 구현해서 사용해보자. 예제에서는 min heap을 구현해본다.
Copy package main
import (
"container/heap"
"log"
)
type IMinHeap interface {
heap . Interface
}
type MinHeap struct {
heap [] uint
}
func (m * MinHeap ) Len () int {
return len (m.heap)
}
func (m * MinHeap ) Less (i, j int ) bool {
return m.heap[i] < m.heap[j]
}
func (m * MinHeap ) Swap (i, j int ) {
m.heap[i], m.heap[j] = m.heap[j], m.heap[i]
}
func (m * MinHeap ) Push (x any ) {
m.heap = append (m.heap, x.( uint ))
}
func (m * MinHeap ) Pop () any {
old := m.heap
n := len (old)
element := old[n - 1 ]
m.heap = old[ 0 : n - 1 ]
return element
}
func main () {
minHeap := & MinHeap {heap: [] uint {}}
heap.Init(minHeap)
heap.Push(minHeap, uint ( 10 ))
heap.Push(minHeap, uint ( 20 ))
heap.Push(minHeap, uint ( 50 ))
heap.Push(minHeap, uint ( 5 ))
log.Println(heap.Pop(minHeap)) // 5
log.Println(heap.Pop(minHeap)) // 10
log.Println(heap.Pop(minHeap)) // 20
log.Println(heap.Pop(minHeap)) // 50
}
Less 조건의 부호만 반대로 바꿔줘도 max heap으로 바꾸어 사용할 수 있어 편하다.
container/ring
다음은 ring이다. ring은 비교적 사용할 일이 많이 없는 듯 보이지만, 알아두면 때때로 도움이 될 수도 있다.
개인적으로는 list를 쓰는 편이긴 하다.
Copy package main
import (
"container/ring"
"fmt"
)
func main () {
data := [] string { "Maria" , "John" , "Andrew" , "James" }
r := ring.New( len (data)) // 노드의 개수를 지정하여 링 생성
for i := 0 ; i < r.Len(); i ++ { // 링 노드 개수만큼 반복
r.Value = data[i] // 링의 노드에 값 넣기
r = r.Next() // 다음 노드로 이동
}
r.Do( func (x interface {}) { // 링의 모든 노드 순회
fmt.Println(x)
})
// "Maria"
// "John"
// "Andrew"
// "James"
}
두 개의 ring을 연결하는 것도 물론 가능하다.
Copy package main
import (
"container/ring"
"fmt"
)
func main () {
data := [] string { "Maria" , "John" , "Andrew" , "James" }
r := ring.New( len (data)) // 노드의 개수를 지정하여 링 생성
for i := 0 ; i < r.Len(); i ++ { // 링 노드 개수만큼 반복
r.Value = data[i] // 링의 노드에 값 넣기
r = r.Next() // 다음 노드로 이동
}
r.Do( func (x interface {}) { // 링의 모든 노드 순회
fmt.Println(x)
})
// "Maria"
// "John"
// "Andrew"
// "James"
newData := [] uint { 1 , 2 , 3 , 4 }
r2 := ring.New( len (newData))
for i := 0 ; i < r2.Len(); i ++ { // 링 노드 개수만큼 반복
r2.Value = newData[i] // 링의 노드에 값 넣기
r2 = r2.Next() // 다음 노드로 이동
}
r3 := r.Link(r2)
r3.Do( func (x interface {}) { // 링의 모든 노드 순회
fmt.Println(x)
})
// John
// Andrew
// James
// Maria
// 1
// 2
// 3
// 4
}
Last updated 5 months ago