시스템 스택과 순환호출(재귀함수)
시스템 스택
- 운영체제가 관리하는 메모리 공간에 스택이라는 영역이 존재한다.
- 이 영역은 함수의 호출과 반환에 사용된다.
- 스택에는 함수가 끝나고 돌아갈 복귀 주소, 호출된 함수에서 사용할 매개변수, 지역변수를 스택에 저장한다.
- 함수가 끝나면, 끝나고 돌아갈 복귀 주소로 돌아간다.
- main()에서 func()를 호출하고 func()에서 sub()를 호출한다면, sub()가 끝나면 func()로 돌아가고, func()가 끝나면 main()으로 돌아간다.
- 이 내용을 가지고 순환 호출로 넘어가자.
순환 호출(재귀함수)
- 순환 호출은 어떤 함수가 자기 자신을 호출하는 프로그래밍 기법이다.
- 자기 자신을 호출한다는 것이 이상하게 느껴질 수 있지만, 함수A가 함수B를 호출하는 것과 함수A가 함수A를 호출하는 것은 같은 원리이다.
- 함수A의 돌아갈 주소에 함수A를 두는 것 뿐이다.
- 문제를 축소시켜가는 것과, 일반화된 규칙을 코드에 대입하는 것이 중요하다.
순환 호출로 팩토리얼 문제 해결하기
- 팩토리얼 문제는 반복문으로 해결할 수도 있지만, 순환 호출로 해결할 수도 있다.
반복 구조로 해결한 팩토리얼
1
2
3
4
5
6
7
8
def factorial_iter(n): # 반복 구조로 구현한 팩토리얼
result = 1
for k in range(2, n+1): # k:2, ..., n
result = result * k # result에 k를 곱함.
return result
print("반복 구조 팩토리얼 : ", end='')
print(factorial_iter(5))
순환 호출로 해결한 팩토리얼
- 팩토리얼을 순환 호출로 해결하는 것은 가장 기본적인 순환 호출 방법이다.
- 팩토리얼은 1부터 n까지 차례로 곱하는데, 결국 (n-1)*n이 n!이라는 것을 그대로 옮기기만 해도 해결된다.
- 즉, 일반화된 규칙을 이해한 후 일반화된 규칙을 코드에 대입해주기만 하면 된다. 이게 재귀 함수의 장점이다.
1
2
3
4
5
6
7
8
def factorial(n): # 순환구조(재귀호출)로 구현한 팩토리얼.
if n == 1:
return 1 # 순환 호출을 멈추는 부분. n이 1이면 답을 알고 있음.
else:
return n * factorial(n-1) # 자신을 순환적으로 호출하는 부분. 문제의 크기는 작아져야 함.
print("순환 구조 팩토리얼 : ", end='')
print(factorial(5))
순환 호출로 해결한 하노이의 탑
- 복잡한 코드여서 스택을 따라가면서 이해하려고 하니 이해하기가 어려웠다.
- 팩토리얼에서 이해한 일반화된 규칙을 이해한 후 일반화된 규칙을 코드에 대입해주기만 하면 된다는 식으로 하는 편이 낫다.
- 하노이의 탑 문제에서는, A가 출발, B가 임시, C가 목표 막대일때, 세 가지 규칙을 따른다.
- A에 있는 n-1개의 원판을 C를 임시 막대로 삼아 B로 이동
- A에 하나 남은 원판을 C로 이동
- B에 있는 n-1개의 원판을 A를 임시 막대로 삼아 C로 이동
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def hanoi_tower(n, fr, tmp, to):
"""
하노이 탑 문제를 해결하는 함수
Parameters:
- n (int): 원판의 수
- fr (str): 시작 막대
- tmp (str): 임시 막대
- to (str): 목표 막대
"""
if(n==1):
print("원판 1: %s --> %s" % (fr,to)) # 순환 호출을 멈추는 부분. 원판이 하나라면 바로 이동.
else:
hanoi_tower(n-1, fr, to, tmp) # 1단계 : fr막대에 있는 n-1개의 원판을 to 막대를 이용해 tmp로 옮김
print("원판 %d: %s --> %s" % (n,fr,to)) # 2단계 : fr에 있는 하나의 원판을 바로 to로 옮김.
hanoi_tower(n-1, tmp, fr, to) # 3단계 : 마지막으로 tmp에 있는 n-1개의 원판을 fr을 이용해 to로 옮김
hanoi_tower(4, 'A', 'B', 'C')
순환 호출로 문자열 뒤집기
- 이 문제 또한 공통된 규칙을 적용하며 문제를 줄여나간다.
- 현재 마지막 단어를 출력한다라는 규칙을 적용하며 msg와 len을 줄여나간다.
1
2
3
4
5
6
7
8
def printReverse(msg, len):
if len>0:
print(msg[len-1])
printReverse(msg, len-1)
instr = "자료구조"
printReverse(instr, len(instr))
print()
참고 자료
This post is licensed under CC BY 4.0 by the author.