프로그래밍에서 인덱스는 왜 0부터 시작할까?

프로필

2025년 01월 26일

104 0

알고리즘 공부를 하면서 가장 의아했던 점 중 하나가 "왜 배열의 첫 번째 요소는 인덱스 1이 아닌 0부터 시작하는가?" 였다. 다음과 같은 리스트가 있다고 가정해보자.

days = ["Mon", "Tue", "Wed", "Thu", "Fri"]

이 리스트의 첫 번째 요소는 "Mon"이고, 두 번째 요소는 "Tue"이다. 그런데 왜 우리가 이 리스트에서 Tue를 찾으려면 days[2]가 아닌 days[1]을 사용해야 할까?

이는 인덱싱은 1이 아닌 0부터 시작하기 때문인데, 보통 우리는 실생활에서 위와 같은 리스트를 보고 Tue의 위치를 묻는다면 2 혹은 두 번째라고 대답할 것이다.

그 이유가 궁금해진 나는 컴퓨터 과학의 기본 원리와 수학적 이점을 찾아보기로 했다. 그 결과 다음과 같은 사실을 알게 됐다.

1. 역사적 배경

C 언어가 0 기반 인덱싱을 채택한 이후로, Python, Java, JavaScript 등 대부분의 현대 프로그래밍 언어들이 이를 따르게 됐다.
이건 프로그래머들이 다른 언어로 전환할 때 혼란을 줄여주는 일관성을 제공한다.

2. 오프셋(Offset) 개념

0 기반 인덱싱의 가장 중요한 개념적 이점은 "오프셋"을 자연스럽게 표현한다는 점이다.

days = ["월", "화", "수", "목", "금"]
         ↑     ↑    ↑     ↑    ↑
         0     1    2     3    4

각 인덱스는 시작점으로부터의 거리를 나타낸다.
- "월": 시작점으로부터 0칸 떨어짐
- "화": 시작점으로부터 1칸 떨어짐
- "수": 시작점으로부터 2칸 떨어짐

3. 메모리 주소 계산의 효율성

배열의 시작 주소가 A이고 각 요소의 크기가 S일 때
- 0 기반 인덱싱: 요소의 주소 = A + (i × S)
- 1 기반 인덱싱: 요소의 주소 = A + ((i-1) × S)

0 기반 인덱싱은 추가 연산(-1)이 필요 없어서 더 효율적이다.

4. 수학적 이점

구간의 길이 계산

  • 시작 인덱스가 0일 때, 구간 [0, N)의 길이는 단순히 N
  • 슬라이싱 작업이 더 직관적임 (예: 처음 3개 요소는 [0:3])

반복문 사용의 단순화

# 0 기반 인덱싱
for i in range(5):  # 0,1,2,3,4
    print(days[i])

# 1 기반이었다면
for i in range(1,6):  # 1,2,3,4,5
    print(days[i-1])  # 매번 -1 필요

실생활의 유사한 예시

  • 자로 길이를 잴 때 0cm에서 시작
  • 디지털 시계는 0:00부터 시작
  • 건물의 지하 층수 (지하 1층, 지하 2층...)

다른 프로그래밍 언어들의 선택

대부분의 프로그래밍 언어가 0 기반 인덱싱을 사용하지만, 몇몇 언어들은 1 기반 인덱싱을 선택했다.

% MATLAB 예시
array = [1, 2, 3, 4, 5];
first_element = array(1);  % 1번째 요소
# R 예시
array <- c(1, 2, 3, 4, 5)
first_element <- array[1]  # 1번째 요소
-- Lua 예시
array = {1, 2, 3, 4, 5}
first_element = array[1]  -- 1번째 요소

이런 언어들이 1 기반 인덱싱을 선택한 이유는 다음과 같다.

  1. 사용자 기반
  2. MATLAB: 주로 수학자, 과학자들이 사용하는데, 이들은 행렬을 1부터 시작하는 수학적 표기법에 익숙함
  3. R: 통계학자들을 위한 언어로, 역시 수학적 직관성을 중시함

  4. 용도의 특수성

  5. 과학 계산, 통계 분석 등 특정 분야에 특화된 언어들은 해당 분야의 관습을 따르는 것이 더 중요했음
  6. 일반 프로그래밍 언어와의 일관성보다 사용자들의 편의성을 우선시함

  7. 설계 철학

  8. "컴퓨터보다 사람이 이해하기 쉬워야 한다"는 철학
  9. 기술적 효율성보다 인간의 직관을 우선시하는 선택

이처럼 모든 언어가 0 기반 인덱싱만이 정답이라고 생각하진 않는다. 각자의 사용 목적과 대상에 맞는 선택을 한 것이다.

수학에서의 0 기반 vs 1 기반

수학에서도 상황에 따라 시작점이 다르다.

  1. 1부터 시작하는 경우
  2. 자연수 집합 (1, 2, 3, ...)
  3. 행렬의 행과 열 번호
  4. 순서를 나타내는 서수 (1st, 2nd, 3rd...)

  5. 0부터 시작하는 경우

  6. 정수 집합 (..., -2, -1, 0, 1, 2, ...)
  7. 좌표계 (0,0)에서 시작
  8. 거리나 변위를 측정할 때
  9. 지수 (x⁰, x¹, x², ...)
  10. 다항식의 차수

특히 컴퓨터 과학과 관련된 수학 분야에서는 0 기반이 더 자연스러운 경우가 많다.
- 이산수학에서의 그래프 이론
- 조합론에서의 경우의 수 계산
- 확률론에서의 사건 공간

따라서 "수학적 직관 = 1 기반"이라고 단순화할 수는 없다. MATLAB이나 R이 1 기반을 선택한 것은 순전히 그들의 주 사용자층이 선호하는 특정 수학 분야(행렬 계산, 통계)의 관습을 따른 것이다.

인간의 직관성 vs 컴퓨터의 효율성

프로그래밍 언어 설계에서 가장 큰 고민 중 하나는 "인간의 직관성"과 "컴퓨터의 효율성" 사이의 균형이다. 0 기반 인덱싱은 이런 트레이드오프를 잘 보여주는 예시다.

직관성을 포기한 대가

처음 프로그래밍을 배우는 사람들이 0 기반 인덱싱에 적응하기 어려워하는 건 당연하다. 우리는 평생 "첫 번째"를 1로 세어왔기 때문이다. 하지만 이런 작은 직관성의 포기는 다음과 같은 이점을 가져왔다.

  1. 더 효율적인 메모리 접근
  2. 더 간단한 범위 계산
  3. 더 적은 CPU 연산

프로그래밍의 본질

결국 프로그래밍은 인간의 생각을 컴퓨터가 이해할 수 있는 방식으로 번역하는 과정이다. 이 과정에서

때로는 인간이 컴퓨터의 방식을 받아들여야 하고, 때로는 컴퓨터가 인간의 방식을 따라야 한다

0 기반 인덱싱은 전자의 좋은 예시다. 처음에는 불편하지만, 이해하고 나면 오히려 더 논리적이고 일관된 시스템임을 깨닫게 된다.

현대 프로그래밍 언어들의 해결 방식

최신 프로그래밍 언어들은 이런 고민을 나름의 방식으로 해결하려 노력한다. Python을 예로 들어보자.

# Python의 경우
days = ["월", "화", "수", "목", "금"]
first = days[0]       # 0 기반 인덱싱 사용
last = days[-1]      # 직관적인 음수 인덱싱 제공
third = days[2]      # 컴퓨터 친화적

이렇게 기본은 컴퓨터 친화적인 방식을 유지하면서도, 음수 인덱싱이나 슬라이싱 같은 인간 친화적인 기능을 추가로 제공한다.

결론

처음 이 글을 쓰게 된 계기는 "왜 컴퓨터의 효율성을 위해 인간이 직관성을 포기해야 하는가?"라는 의문이었다. 검색을 통해 알게 된 1 기반 인덱싱 언어들의 설계철학을 보면서 난 현재 Python 개발자지만 저 언어들의 설계철학에 크게 공감했다.

하지만 이를 깊이 파고들면서 깨달은 게 있다. 프로그래밍의 본질은 결국 인간의 생각을 컴퓨터가 이해할 수 있는 방식으로 번역하는 과정이다. 우리가 개발자로서 하는 일은 컴퓨터와 대화하는 것이고, 때로는 우리가 컴퓨터의 언어를 배워야 할 필요가 있다.

0 기반 인덱싱은 처음에는 불편하고 비직관적으로 느껴질 수 있다. 우리는 평생 "첫 번째"를 1로 세어왔으니까. 하지만 이런 작은 직관성의 포기는 더 효율적인 메모리 접근, 더 간단한 범위 계산, 더 적은 CPU 연산이라는 이점을 가져왔다.

이제는 어느정도 이해할 수 있게 되었다. 0 기반 인덱싱은 단순한 관습이나 C 언어의 유산이 아니라, 컴퓨터 과학의 기본 원리와 잘 맞는 논리적인 선택이었다는 것을. 그리고 이런 선택이 현대 프로그래밍의 발전을 이끌어왔다는 것을.

결국 좋은 프로그래밍 언어란 인간의 직관성과 컴퓨터의 효율성 사이에서 적절한 균형을 찾는 것이 아닐까? 0 기반 인덱싱은 그 균형점을 찾아가는 과정에서 나온 하나의 해답이었던 것이다.

#인덱스 #리스트 #오프셋

댓글 개

댓글을 작성하려면 로그인이 필요합니다