Recursive 함수를 stack 을 사용하지 않고 푸는 방법이 있을까요?

Yoons의 이미지

Ackermann 함수를 잠시 보게 되었는데..
Recursive function 의 대표적인 예... 로 예제로 나온걸 보았습니다.

non-recursive function 을 짜는 방법을 고민하던 중에..
주변에서 stack 을 대신하여 다중 for문을 이용하여 푸는 방법이 있다고 하던데..
과연 그런 방법이 있을까요..?

// 뱀다리..
뿐 아니라 array 를 이용하는 방법, 등등..
주변에서는 말만 많더군요.. 쳇..;;

그리고 Ackermann 을 알고픈 분은 wiki 에서 찾으시면... (영문)
다양한 언어의 Ackermann 과 C based non-recursive Ackermann 을 볼 수도 있더군요..

whitelazy의 이미지

recursion을 계속하면 함수를 계속 호출하게되고 당연히 스택에 계속 쌓입니다...
이런걸 벗어나기위해서 for문으로 대치하는 거를 말씀하시는듯합니다.
recursion은 결국 반복해서 함수를 호출하는걸로 단순하게 생각할수 있고 '반복'이란거에 포커스를 맞추면 당연히 loop문으로 대치할수 있습니다
재귀호출시의 종료 조건을 반복문의 종료조건으로 두고 계산하시면 되겠죠 배열은 아마 for문의 계산결과를 배열에 저장하는걸 말하는건 아닐지.. 싶습니다만..

결론은 재귀호출은 반복문으로 변경 가능합니다..
스택은 계산값 저장을 위한건지 아니면 함수호출시 소모되는 스택을 말씀하시는건지 모르겠습니다. 저도 말만하고 끝난거같긴하지만 이해 안가시면 간단한 재귀 문을 반복문으로 변경해 보시면 아실듯 합니다

//뱀다리...
써넣고보니 이미 찾아보신 부분의 코드들에서 다 구현되어 있을법합니다만.....;; 물론 제가 찾아본것은 Ackermann function만입니다만.. 위키피디아에서요..

Quote:
다양한 언어의 Ackermann 과 C based non-recursive Ackermann 을 볼 수도 있더군요..
이 코드에서 스택을 사용하나요?
기존의 연산값을 가져와야하는부분이야 배열에 저장하시면 되겠구요.. 몇번째 값을 가져오실것 아니라면 그냥 바로 이전결과만 저장하면 되지 않나요..
winner의 이미지

상품으로서의 code에서는 recursion 제거가 필요하다고 주장하시는 분들도 있지만
그 code는 너무 비직관적이 되기 마련입니다.

또한 stack 동장을 배열같은데다가 수동으로 작업을 해줘야 할 가능성이 큽니다.

확실히 성능은 좋아질 지도 모릅니다.

저도 예전에 8 Queen 이나 하노이의 탑을 반복으로 풀어본 적이 있는데요.
수동의 stack 동작과 함께 loop을 쓰는 것에 compiler 최적화를 하면 재귀호출의 두배정도의 성능이 나오더군요.
(입출력은 제외한 경우입니다.)

하지만 가장 큰 문제는 함수 내에서 재귀호출이 몇번 호출되느냐에 따라 stack 동작의 구체적 방식이
달라지기 때문에 정형화된 recursion -> loop with array 가 없다는 것입니다.

혹시 아시는 분 있다면 저도 꼭 부탁드립니다.
이 문제는 저도 한 때 굉장히 고심했던 문제입니다.

totohero의 이미지

단지 stack 동작을 emulation하기 위한 용도로 배열을 사용한다면 그 성능은 재귀 호출과 별반 다를 바 없을 테고, 말씀하신대로 stack을 흉내내기도 까다로울 수 있죠. Ackermann 함수 등이 문제되는 이유는 재귀가 두 갈래 이상이어서 했던 계산을 또 하는 바람에 원래 필요한 계산 시간보다 (worst case) exponential배로 큰 시간이 든다는 점입니다. 따라서 배열을 hash map 등으로 구현하여 윗분이 언급한 것처럼 이전 계산값을 저장하는 것이 맞겠죠. Ackermann 함수처럼 side effect가 없고 최종 값을 얻기만 하면 된다면 일반화하긴 쉬울텐데요.

F(n) = G ( F(n-a), F(n-b), F(n-c), ...) 와 같은 재귀 형식을 iteration을 이용하여 구현한다면 (F의 인자는 자연수, a, b, c 등도 자연수)

HashMap memo; // 어떤 v에 대해 F(v)가 미리 계산되어 있으면 memo[v] = F(v) 이다. 초기값 memo[1], memo[2] 등 몇개는 미리 저장되어 있다.

F(n) =
1. memo[n]이 존재하면 끝
2. memo[p]는 존재하나 memo[p+1]이 아직 계산되지 않은 1~n 사이의 수 p를 찾는다.
3. memo[p+1]부터 memo[n]까지 loop을 돌며 계산한다. 이때 p+1~n 사이의 수 i에 대해 memo[i] = G (memo[i-a], memo[i-b], memo[i-c], ..)로 계산하면 된다.

정태영의 이미지

call stack 을 이용하지 않고, 사용자가 stack 을 만들어 사용함으로 recursive call 을 없앨 수 있습니다.

stdcall 의 경우 함수가 호출되게 되면, arguments 와 pc 가 call stack 에 쌓이게 됩니다. 또한 지역 변수 또한 stack 에 쌓이게 되는데, call stack 을 사용하지 않고, 꼭 필요한 정보만을 자신이 관리하는 (효율적인) stack 에 쌓게 되면 조금 더 가벼운 구현이 가능하겠죠. 단 아주 잘짜야 할겁니다. ;) 요새 컴파일러들 굉장히 똑똑하거든요.

인자가 적다면 (2개이하) fastcall 을 사용할 경우 call stack 을 사용하지 않게 되서, recursive call 이 상당히 빠르게 구현될 수 있습니다. 함수의 내부 변수가 많다면 register 의 일부가 stack 에 백업되게 될테니 이런 부분에선 non-recursion call 을 사용하는게 조금 유리할 지 모르겠네요. (caller save 일 경우야 모든 레지스터가 백업되겠지만, callee-save 라면 일부 레지스터 만을 백업하겠죠. 단 -O0 옵션이라면 변수를 레지스터로 매핑하지 않으므로 딴세상 이야기)

뭐 결국 원리를 알고, 문제점과 자신이 사용하는 툴(언어?)들이 지원하는 규약들을 상세하게 알고 있다면 non-recursive call 을 사용하는것이나 recursive call 을 사용하는 것이나 다 충분히 빠르고 효율적으로 만들 수 있습니다.

--
오랫동안 꿈을 그리는 사람은 그 꿈을 닮아간다...

http://mytears.org ~(~_~)~
나 한줄기 바람처럼..

오랫동안 꿈을 그리는 사람은 그 꿈을 닮아간다...

http://mytears.org ~(~_~)~
나 한줄기 바람처럼..

vacancy의 이미지


Memoization으로 recursion을 없앨 수 있다면
dynamic programming으로 해결 가능하겠지요.

하지만 일반적인 방법은 없을 것 같습니다. -_-a
되는 문제가 있고, 안되는 문제가 있겠지요.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.