배열과 슬라이스

김대익·2022년 4월 18일
0

배열과 슬라이스

배열, 슬라이스 모두 연속된 메모리공간을 순차적으로 이용하는 자료구조
배열은 메모리 공간 그자체지만, 슬라이스는 배열을 가리키는 구조체이다.

fruits := make([]string, 3, 5)
fruits[0] = "사과"
fruits[1] = "바나나"
fruits[2] = "토마토"


슬라이스에 용량이라는 개념이 있는 이유는 배열은 연속된 메모리공간을 쓰기때문에 내용을 추가하고 싶을 때
사용하던 메모리공간 뒤쪽이 이미 사용중이라면 원하는 크기의 다른 메모리공간을 찾아야 새로 배열을 만들어야하기 때문에 효율이 좋지않기 때문이다.

위에서처럼 배열은 [...]string{"사과", "바나나", "토마토"}처럼 미리 자료형과 크기를 지정하기 때문에 append를 못하고 유연하지 못하다.
슬라이스는 포인터로 새로운 배열을 가리키면 되기 때문에 배열 크기가 가변적이다

append를 이용해 기존 슬라이스에 덧붙이는 방법은 fruits = append(fruits, "포도")처럼
기존 슬라이스 = append(기존 슬라이스, 추가하고 싶은 값, 추가하고싶은 값, ...) 으로 쓰면 된다.


슬라이스 복사

func Example_sliceCopy() {
	src := []int{30, 20, 50, 10, 40}
    dest := make([]int, len(src))
    for i, slice = range src {
    	dest[i] = src[i]
    }
    fmt.Println(dest)
    // Output: [30 20 50 10 40]
}

위와 같이 for문을 이용하는 방법말고
copy함수를 이용한 방법이 있다
copy(dest, src)를 이용하면 복사가 되지만
len(src), len(dest)중 더 작은 길이만큼만 복사한다


슬라이스 삽입, 삭제

golang 삽입/삭제 메서드는 따로 없기 때문에 몇가지 패턴을 이용해야한다.

첫번 째로 append를 이용한 패턴이다.

a = append(a[:i+1], a[i:]...)
a[i] = x

if i < len(a) {
	a = append(a[:i+1], a[i:]...)
    a[i] = x
} else {
	a = append(a, x)
}

이는
a = append(a, x) 중간에 삽입하는 경우 외에 맨 오른쪽에 추가하는 경우도 고려한 코드이다.

두번 째로 copy를 이용한 다른 패턴을 보면

a = append(a, x)
copy(a[i+1:], a[i:])
a[i] = x


여러개를 삽입할 때는

a = append(a, x...)
copy(a[i+len(x):], a[i:])
copy(a[i:], x)

copy(a[i+1:], a[i:])에서 +1이 아닌 +len(x)을 한 점이 다르다


삭제의 경우

a = append(a[:i], a[i+1:]...)

여러개를 삭제하고 싶다면
a = append(a[:i], a[i+k:]...) 앞에서처럼 +1대신 +k를 하면된다.

만약 순서가 바뀌어도 된다면 O(n)의 시간복잡도를 가진 앞의 방법들과 다르게 O(1)만 걸리는 패턴이 있다.

a[i] = a[len(a)-1]
a = a[:len(a)-1]

위 방법으로 여러개를 지우는 경우는

start := len(a) - k
if i + k > start {
	start = i + k
}
copy(a[i:i+k], a[start:])
a = a[:len(a) - k]


메모리 문제를 해결한 코드는 아래와 같이 삭제하는 값들을 nil로 바꾼다

copy(a[i:], a[i+k:])
for i := 0; i < k; i++ {
	a[len(a)-1-i] = nil
}
a = a[:len(a)-k]

0개의 댓글