카테고리 없음

그림으로 보는 재귀 함수(Recursion): 개념부터 필수 종료 조건까지

머니지니87 2026. 3. 1. 15:44
반응형

자료구조의 기초를 다지고 알고리즘의 세계로 깊숙이 발을 내디딜 때, 모든 입문자가 한 번쯤은 머리를 쥐어뜯게 만드는 거대한 벽이 하나 등장합니다. 바로 '재귀 함수(Recursion)'입니다. "함수가 자기 자신을 호출한다고요? 그럼 끝도 없이 계속 실행되는 거 아닌가요?"라는 의문이 드는 것은 지극히 정상입니다. 뇌 구조가 거부 반응을 일으키는 이 기묘한 프로그래밍 기법은 사실 복잡한 트리 구조를 탐색하거나, 복잡한 수학 연산을 몇 줄의 우아한 코드로 압축해 내는 컴퓨터 과학의 꽃입니다. 오늘은 머릿속을 맴도는 재귀 함수의 개념을 러시아 전통 인형에 빗대어 그림을 그리듯 아주 명확하게 시각화하고, 시스템 다운을 막기 위한 필수 규칙까지 완벽하게 정립해 드리겠습니다.

1. 재귀 함수란 무엇인가? (Self-Reference)

재귀(Recursion)의 사전적 의미는 '원래의 자리로 되돌아가거나 되돌아옴'입니다. 프로그래밍에서 재귀 함수란 자신의 함수 본문(Body) 내부에서 다시 자기 자신의 함수 이름을 호출하여 실행하는 형태의 함수를 말합니다. 이 난해한 개념을 가장 직관적으로 이해할 수 있는 예시가 바로 러시아의 전통 인형 '마트료시카(Matryoshka)'입니다.

1-1. 마트료시카 인형을 여는 과정

커다란 나무 인형의 뚜껑을 열었더니, 그 안에 똑같이 생긴 크기만 약간 작은 인형이 들어있습니다. 그 작은 인형을 열었더니 또 더 작은 인형이 나옵니다. 이 행위는 언제 끝날까요? 더 이상 반으로 쪼개질 수 없는, 아주 작은 통나무 인형이 나올 때까지 계속됩니다. 그리고 마지막 인형을 확인한 후에야 비로소 열어두었던 인형들을 가장 작은 것부터 역순으로 하나씩 덮으며(조립하며) 처음의 큰 인형으로 돌아가게 됩니다. 재귀 함수는 거대한 문제를 동일한 형태의 더 작은 문제로 쪼개가며 파고들다가, 답을 찾으면 다시 껍질을 덮으며 올라오는 완벽한 마트료시카 구조입니다.

2. 재귀 함수의 생명줄: 2가지 필수 구조 조건

재귀 함수를 코드로 작성할 때 단 한 줄이라도 실수하면 프로그램은 그 즉시 멈춰버립니다. 브레이크가 고장 난 스포츠카를 타지 않으려면 다음 두 가지 논리 구조를 함수 안에 반드시 명시해야 합니다.

2-1. 기저 조건 (Base Case): 브레이크 페달

재귀의 가장 핵심이자 가장 먼저 작성해야 하는 부분입니다. 더 이상 자기 자신을 호출하지 않고, 명확한 결과값을 반환하며 재귀의 고리를 끊어내는 탈출구입니다. 마트료시카에서 '속이 비어있어 더 열리지 않는 마지막 통나무 인형'에 해당합니다. 이 기저 조건에 도달하지 못하도록 코드를 짜면 함수는 영원히 자기를 호출하며 무한 루프에 빠지게 됩니다.

2-2. 재귀 단계 (Recursive Case): 엑셀 페달

실질적인 연산이 이루어지며, 자기 자신을 다시 호출하는 부분입니다. 여기서 반드시 지켜야 할 철칙은 "호출할 때마다 전달하는 매개변수(Parameter)의 값이 반드시 기저 조건(탈출구)을 향해 가까워져야 한다"는 것입니다. 10에서 시작했다면 9, 8, 7... 이렇게 깎여나가야 언젠가 기저 조건인 0에 도달하여 브레이크가 걸릴 수 있습니다.

3. 스택 메모리로 보는 재귀의 내부 동작 (콜 스택)

컴퓨터 내부에서는 재귀 함수를 어떻게 처리하고 기억할까요? 바로 스택(Stack) 메모리를 사용합니다.

예를 들어, 3부터 1까지 카운트다운을 하는 재귀 함수 `count(3)`을 호출했다고 가정해 봅시다.

  1. 컴퓨터는 `count(3)`의 작업 상태를 일시 정지하고 메모리 스택에 Push(저장) 합니다. 그리고 내부에서 부른 `count(2)`로 진입합니다.
  2. `count(2)` 역시 끝나지 않고 `count(1)`을 부르므로, `count(2)`를 스택 위에 Push 합니다.
  3. 드디어 `count(1)`이 기저 조건을 만나 작동을 마치고 반환(Return)을 시작합니다!
  4. 이제 컴퓨터는 메모리 스택에서 Pop(꺼내기)을 시도합니다. 스택의 꼭대기에 있던 `count(2)`를 꺼내어 남은 작업을 마무리하고 닫습니다.
  5. 마지막으로 스택 바닥에 대기 중이던 최초의 `count(3)`을 꺼내어 작업을 완전히 종료합니다.

만약 기저 조건이 없어서 수십만 번 재귀가 반복되면 어떻게 될까요? 저장 공간인 콜 스택(Call Stack)이 허용된 메모리 용량을 초과하여 넘쳐흐르게 됩니다. 우리가 개발 중에 지겹도록 보게 될 그 유명한 에러 메시지, 'Stack Overflow(스택 오버플로우)'가 바로 이렇게 발생하는 것입니다. 따라서 깊이가 너무 깊어질 것으로 예상되는 로직은 재귀 함수 대신 일반적인 `for` 반복문으로 대체하여 짜는 것이 엔지니어의 올바른 판단입니다.

[핵심 요약]
1. 재귀 함수는 큰 문제를 해결하기 위해 함수 본문 안에서 자기 자신을 다시 호출하여 작은 문제로 쪼개어 나가는 프로그래밍 기법입니다.
2. 무한 루프로 인한 스택 오버플로우(Stack Overflow) 에러를 방지하려면, 조건 달성 시 탈출하는 기저 조건(Base Case)을 반드시 명시해야 합니다.
3. 복잡한 자료구조(트리 탐색, 그래프) 알고리즘을 구현할 때 코드를 극도로 간결하게 만들어주는 필수 도구입니다.
반응형