본문 바로가기
프로그래밍/Algorithm

배열(Array)에 대해서

by bantomak 2023. 9. 20.

순서 있게 값을 저장

배열의 가장 중요한 특징은 값을 인덱스(index)를 사용하여 순서 있게 저장한다는 것이다.

그래서 이 인덱스를 통해서 특정 위치에 저장되어 있는 값을 상수 시간(O(1))에 읽고 쓸 수 있다.

 

예를 들어, 다음과 같은 형태로 값이 저장되어 있는 배열 'arr'가 있을 때,

 

value: A B C D E F G H I J
index: 0 1 2 3 4 5 6 7 8 9

 

인덱스 3에 있는 값을 'D'에서 'K'로 변경해 보겠습니다.

print(arr[3]) # 'D'
arr[3] = 'K' # 인덱스 3에 있는 값을 'D'에서 'K'로 변경
print(arr[3]) # 'K'

 

이와 같이 대부분 프로그래밍 언어에서는 배열이 가리키고 있는 변수명 뒤에 대괄호를 붙여서 'arr [i]'와 같은 형태의 문법으로 배열에 저장되어 있는 값에 접근하거나 갱신한다.

 

단, 배열의 크기를 초과하는 인덱스를 사용하는 경우 예외가 발생한다.

 

arr[10] # Index Error

 

같은 값을 중복해서 저장

배열에는 동일한 값을 여러 번 저장할 수 있다. 값이 돌일하더라도 인덱스가 달기 때문에 데이터의 중복이 전혀 문제 되지 않는다.

 

예를 들어, 다음의 배열에는 'A'가 1개, 'B'가 2개, 'C'가 3개, 'D'가 4개 저장되어 있다.

value: A B B C C C D D D D
index: 0 1 2 3 4 5 6 7 8 9

 

만약에 배열에서 중복되는 값을 제거해야 한다면 세트(set) 자료구조를 사용하면 된다.

 

배열 순회

배열에 저장된 모든 값에 접근하기 위해서는 루프를 돌아야 한다.

전통적으로 for문을 사용하여 인덱스 i를 통해서 값에 접근하는 코딩 패턴이 많이 사용된다.

 

예를 들어, 자바스크립트에서 'arr' 배열에 저장된 모든 값을 콘솔에 출력하는 코드는 다음과 같이 작성할 수 있다.

 

for (let i = 0; i < arr.length; i++) {
  console.log(arr[i]);
}

 

최근에는 함수형 프로그래밍이 보편화되면서 foreach()와 같은 함수를 이용하는 경우도 어렵지 않게 볼 수 있다.

 

예를 들어, 자바스크립트의 배열에서 제공하는 foreach() 함수를 사용하여 위 코드를 재작성해 보자

arr.forEach(console.log);

 

배열의 크기

일반적으로 배열은 메모리에서 특정 부분을 선점하기 때문에 배열에 저장할 수 있는 값의 개수는 고정되게 된다.

예를 들어, 자바에서 빈 배열을 생성할 때는 'Array()' 생성자에 배열의 크기를 인자로 넘긴다.

 

char[] array = new char[10];

 

따라서 배열은 저장해야 할 값의 개수를 미리 알 수 없을 때는 매우 비효율적인 자료구조이다. 왜냐하면 배열의 크기를 초과하는 개수의 값을 저장하기 위해서는 새로운 배열을 만들어서 기존의 배열에 있던 모든 값을 복사해야 하기 때문이다.

 

char[] newArray = new char[array.length * 2];

for (char i = 0; i < array.length; i++) {
    newArray[i] = array[i];
}

newArray[10] = 'K';

 

파이썬이나 자바스크립트처럼 이 부분에 대해서 덜 엄격한 프로그래밍 언어에서는 배열의 크기가 동적으로 늘어나기도 한다.

 

중간에 있는 값 삽입/삭제

값을 맨 뒤가 아니라 중간에 삽입하거나 삭제해야 한다면 배열은 자료구조로서 최악의 선택이 될 수 있다. 왜냐하면 기존에 저장되어 있는 많은 값들을 모두 한 칸씩 밀어줘야 하는 shift 작업이 수반되는데 이 작업이 매우 비효율적이기 때문이다.

 

예를 들어서, 다음과 같이 10개의 알파벳이 저장되어 있는 배열이 저장되어 있다고 가정해 보자.

 

const arr = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"];

 

이 중 인덱스 3에 있는 'D'를 삭제해야 한다면 어떻게 해야 할까? 삭제 후에 'F'부터 'J'까지의 모든 알파벳이 왼쪽으로 한 칸씩 이동시켜줘야 한다.

 

delete arr[3]; // `D` 삭제

for (let i = 4; i < arr.length; i++) {
  arr[i - 1] = arr[i]; // 한 칸씩 왼쪽으로 이동
}

arr.pop(); // 마지막 값 버림

 

이렇게 값을 중간에서 삭제하거나 삽입해야 할 일이 많다면 링크드 리스트(Linked List)가 좋은 대안이 될 수 있다.

 

정리

배열은 값을 순서 있게 저장하는 자료구조로써 인덱스를 통해 매우 빠르게 값에 접근하거나 갱신할 수 있다. 하지만 값을 맨 끝이 아닌 중간에서 삭제하거나 삽입해야 할 때는 적합하지 않은 자료구조이다.

 

출처

 

알고달레

알고리즘 입문자를 위한 달레의 친절한 안내서

www.algodale.com

댓글