728x90
#include <stdio.h>
int recursive_ackermann(int m, int n) {
	if (!m)
		return n + 1;
	else if (!n)
		recursive_ackermann(m - 1, 1);
	else
		recursive_ackermann(m - 1, recursive_ackermann(m, n - 1));
}

int loop_ackermann(int m, int n) {
    int stack[1000], top = 0, current = 0;
    stack[0] = m;

    while (top >= 0) {
        current = stack[top]; //현재 top이 가르키고 있는 값
        if (current == 0) // 그 값이 만약 0이라면
        {
            n++; // n을 n+1로 업데이트
            top--; //top를 한칸 뒤로 옮김
        }
        else if (n == 0) {
            n = 1;
            stack[top] = current - 1;
        }
        else{
            n--; //n을 n - 1로 업데이트
            stack[top] = current - 1; //지금 top칸을 m - 1로 업데이트
            stack[++top] = current; //그 다음 top칸을 m으로 업데이트
        }        
    }
    return n;

}

int main(int argc, char* argv[]) {
	int m,n;
	scanf_s("%d %d", &m, &n);
    printf("achkermann with recursive : %d\n", recursive_ackermann(m, n));
	printf("achkermann with loop : %d\n", loop_ackermann(m, n));
}

재귀함수를 반복문으로 구현하는 방법중 하나로 스택을 이용할 수 있다.

 

위 ackermann은 m,n값의 조건에 따라서, f(m,n)으로 표현되는데 

m != 0 && m!= 0인 경우, f(m-1,f(m,n-1))로 표현된다.

 

재귀함수를 이용할 경우, 언어 그대로 작성하기에 작성 속도는 빠르지만, 함수 호출이 많으므로 m,n값이 커지면 반복문에 비해 비효율적이다. 

 

위 ackermann은 최종적으로 m = 0일때 함수가 종료되고, 반환하는 값은 n이다. 즉, 이 함수의 리턴값은 결국 n이고, 생각해야할 변수는 m이다. 

 

함수를 합성함수라 생각하면, f(m-1,f(m,n-1))의 경우,

현재 가르키는 값은 m이 되어야 하고( f(m,n-1)값을 먼저 계산해야 하기에), 

위의 계산 후 가르켜야 할 값은 m - 1이다. ( f(m-1,*) , *은 위의 식 연산의 결과)

 

요약하면, 함수의 합성 연산이 진행될수록 연산시 사용할 m의 값이 쌓이는데

나중에 쌓인 m의 값을 먼저 연산에 사용하므로 stack을 사용한다.(반대의 경우는 큐)

 

 재귀함수를 반복문으로 표현한다는 것은

 할 일을 미뤄두는 느낌으로, 어떠한 저장공간에 연산에 필요한 값을 저장하고,

저장 방식은 함수의 합성과 같이 어떠한 연산의 패턴에 따라 바뀌는 것 같다고 생각한다.

728x90

'자료구조론' 카테고리의 다른 글

fibonacci  (0) 2023.03.30
factorial  (0) 2023.03.30
check_perfectNumber  (0) 2023.03.30
binomial_coefficient  (0) 2023.03.30
비둘기 집  (0) 2023.03.30

+ Recent posts