시작하며
2학년 2학기에 들은 수업에서 우연찮게 Go를 접하게 되었다. 생각보다 다른 언어들에 비해 배우기도 어렵지 않았고 사용하는 것도 어렵지 않았다. 큰 틀이 C와 유사해서 그런것 같기도 하고…
Go언어를 사용하는 개발자가 가장 연봉이 높다는 말도 있고(Go를 쓰는 개발자가 구글 개발자라 그렇다는 말도…), 꿈은 데이터 사이언티스트지만 많은 언어를 배우고 다루는 것에 관심이 많다보니 Go를 익숙하게 만들기 위해 Go로 자료구조를 만들어 보자.
배열 (Array)
배열의 기본 구조는 크기를 선언하고 인덱스 접근, 데이터 삽입, 데이터 제거, 특정 인덱스 값 변경 등등을 기능으로 가져야 한다.
자료구조의 정확한 내용은 C++로 작성한 자료구조 포스트를 참고하길 바란다.
구현
우선 고민이 되었던 것은 Go에는 클래스가 없다. Go로도 객체지향 프로그래밍을 할 수 있다. 클래스는 없지만 다행히 구조체는 존재한다. 활용방법과 메소드 선언도 거의 유사하다. 일단 직접 부딪혀보자.
구조체 선언
1
2
3
4
5
type Array struct {
n int // array save count
arraySize int // full size
arr []int
}
본격적으로 배열의 역할을 할 구조체이다. 배열의 메인 역할은 arr이 맡게된다. 생성자를 만들어보자. Go에서 생성자는 조금 다른 방식으로 구현한다.
생성자
1
2
3
4
5
6
7
8
9
10
11
12
func NewArray(arraySize int) *Array {
a := Array{}
a.n = 0
a.arraySize = arraySize
a.arr = make([]int, arraySize)
for i := 0; i < arraySize; i++ {
a.arr[i] = 0
}
return &a
}
Go는 c++에서 new나 delete같은 함수가 없다. (사실 있다. 나중에 알아보니까 근데 여기서는 크기를 지정하는 생성자가 필요하므로 생성자를 만들어준다. new(struct)
로 작성하면 모든 필드가 0으로 초기화되어 생성된다.)new()
는 기본생성자라고 보면 된다.
그래서 생성자를 만들 때 포인터를 활용해서 변환된 객체를 반환해주는 코드를 작성한다. 그래서 return값이 객체 포인터 값으로 지정된다. 이 자체로 new와 같은 역할을 한다. delete는 해당 객체를 nil로 만들면된다.
인덱스 참조 함수
1
2
3
func (a *Array) at(idx int) int {
return a.arr[idx]
}
맨 처음에는 리시버의 대상(a *Array
)을 포인터 리시버가 아닌 value 리시버(a Array
)의 형태로 모든 메소드 함수를 작성했다. 그러다보니 값을 설정하는 함수에서 해당 구조체의 값을 바꾸지 못했다.
특정 값을 변경하고 싶다면 포인터 접근을 잊지말아야한다.
add, set함수
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
func (a *Array) add(idx int, data int) {
if a.arr[idx] == 0 {
a.arr[idx] = data
a.n++
}else {
for i := a.n; i > idx; i-- {
a.arr[i] = a.arr[i-1]
}
a.n++
a.arr[idx] = data
}
}
func (a *Array) set(index int, data int) {
if a.arr[index] != 0 {
a.arr[index] = data
}else {
fmt.Println(0)
}
}
기본적인 추가 함수는 한칸씩 값을 밀어내는 것이다. 그래서 맨 끝에 저장된 곳에서부터 뒤로 값을 댕겨온다고 생각하면 편하다.
set함수는 간단하다 그냥 해당 인덱스 직접 접근하면 끝이다.
remove 함수
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func (a *Array) remove(idx int) {
if a.arr[index] == 0 {
fmt.Println(0)
}else {
ret := a.arr[index]
for i := index; i < a.n; i++ {
a.arr[i] = a.arr[i + 1]
}
a.arr[a.n] = 0
a.n--
fmt.Println(ret)
}
}
지우는 것은 add의 역방향 연산으로 진행하면된다. 뒤에서 앞으로 댕겨오면 되는 것이다.
자세한 전체 코드는 깃허브를 참고하길 바란다.
Comments powered by Disqus.