재귀 —“분할 및 정복”또는“코드 재사용”


11

우리 모두가 알고 있듯이 재귀 는 그러한 문제 중 하나입니다. 머릿속을 감싸는 것은 프로그래밍 항해에서 "마일스톤"을 달성하는 것처럼 느껴집니다.

그러나 실제 문제에서 실제로 사용하는 경우 재귀의 메커니즘을 알면 충분하지 않습니다. 재귀가 가장 적합한 솔루션 인 문제의 본질도 이해해야합니다.

내 질문은 이것입니다 ...

  • 재귀의 해결을 요구하는 "문제 패턴"은 무엇인가
  • 재귀는 "분할 및 정복"전략의 형태 또는 "코드 재사용"의 형태이거나, 또는 그 자체의 디자인 패턴입니다.
  • 재귀가 즉각적인 해결책으로 떠오르는 실제 문제의 예를 들어 주시겠습니까?

-업데이트-

많은 답이 "진정한 문제"를 나무 횡단, 계승 등으로 언급하고 있습니다. 저는 "진짜 실제 문제"를 선호합니다. 예를 들어 보겠습니다 ...

우리는 큰 텍스트 척 (링크 된 목록으로 약 30MB의 텍스트 structs)을 가지고 있었고, 전체 텍스트 검색을 위해 인덱스를 만들어야했습니다. 전체 인덱스를 메모리에 유지하고 10 분마다 텍스트를 다시 인덱싱해야했습니다.

10 분마다 전체 텍스트 (2 개의 링크 된 목록, 한 줄씩)를 새로 생성 된 텍스트 덩어리와 비교하여 변경된 줄을 확인한 다음 해당 줄만 다시 색인을 생성합니다. 전체 텍스트를 다시 색인화하지 않아도됩니다. 두 개의 30MB 링크 된 목록 사이의 차이점을 찾아야했습니다.

내 동료 중 한 명이 HEAVY 재귀를 사용하여 선을 비교 한 다음 척이 배열에서 다른 위치를 수집하는 환상적인 프로그램을 생각해 냈습니다. 그렇습니다. 그게했다.

요점은-재귀를 많이 사용 하여이 문제를 현명하게 해결할 수 있음을 어떻게 알 수 있습니까?


요즘 대부분의 컴퓨터에는 GB의 RAM과 TB의 하드 드라이브 공간이있는 30MB가 실제로 큰가요?
JB King

30MB는 크지 않을 수 있지만 텍스트가 크래킹 된 데이터 구조의 종류를 고려할 때 실제로는 PROCESS 및 DIFF에 대한 텍스트의 큰 척이었습니다.
treecoder

3
"폴더 구조를 트래버스"하는 것이 실제로 실제적이지 않습니까? 그리고 나는 당신의 예에서 재귀가 직관적이지 않은 방법과 그 사용이 특히 주목할만한 이유를 완전히 알지 못합니다. 동료는 다른 알고리즘과 마찬가지로 재귀 알고리즘을 설계했습니다. Hoare가 정렬 문제를 재귀 적으로 해결하는 아이디어를 어떻게 얻었는지 물을 수도 있습니다.
Konrad Rudolph

2
"동일한 일련의 작업을 불확정 한 횟수로 실행"으로 "코드 재사용"을 의미한다고 생각하는 것이 맞습니까? 그것은 다른 곳에서 사용하기 위해 일반적인 코드를 작성한다는 의미에서 "코드 재사용"과 반대입니다.
앤디 헌트

4
그러나 나무 통과는 "실제 문제"이며 많은 사람들이 거의 매일 접하게됩니다.
팔콘

답변:


16
  • 재귀의 해결을 요구하는 "문제 패턴"은 무엇인가

나는 재귀 사용에 대한 문제 패턴과 같은 것이 없다고 말하지 않을 것이다. 재귀로 구현할 수있는 모든 함수는 종종 스택을 밀고 터지는 방식으로 반복적으로 구현할 수 있습니다.

표현과 성능의 문제입니다. 반복 알고리즘은 종종 성능이 향상되고 최적화하기가 더 쉽습니다. 그러나 재귀 알고리즘은보다 명확한 표현의 이점을 얻으므로 읽기, 이해 및 구현이 더 쉽습니다.

예를 들어, 재귀 없이는 표현할 수없는 것들도 있습니다. 소위 기능적 언어는 자연스런 표현 방식이기 때문에 재귀에 크게 의존합니다. "재귀 프로그래밍은 기능적 프로그래밍이 올바르게 수행된다"는 것입니다.

  • 재귀는 "분할 및 정복"전략의 형태 또는 "코드 재사용"의 형태이거나, 또는 그 자체의 디자인 패턴입니다.

나는 그것을 디자인 패턴이라고 부르지 않을 것이다. 표현의 문제입니다. 때로는 재귀 표현이 더 강력하고 표현력이 좋으므로 코드가 더 깨끗하고 깨끗해집니다.

  • 재귀가 즉각적인 해결책으로 떠오르는 실제 문제의 예를 들어 주시겠습니까?

트리를 통과해야하는 것은 재귀 알고리즘으로 올바르게 표현됩니다.


7
"재귀로 구현할 수있는 모든 기능은 종종 스택을 밀고 터지는 방식으로 반복적으로 구현할 수 있습니다." 결국 스택 기반 메모리를 사용하는 언어에서는 재귀를 사용할 때 함수 데이터를 스택에서 올리거나 내립니다.
JAB

기계에 의해 언어를 컴파일하거나 해석하는 경우에만 ;-) 또한 매우 높은 관점에서, 표현과 언어는 기계와 하드웨어 및 OS와 완전히 독립적이므로 반드시 스택이 필요하지 않습니다.
팔콘

아 맞아요 "스택 기반 메모리를 사용하는 언어 / 언어 컴파일러 구현에서"라고 말 했어야합니다.
JAB

일반적으로 말하면 그렇습니다. 나는 nitpicking을 보이고 싶지 않았다.
팔콘

2
무한 목록 재귀없이, 적어도 재귀 구현없이 표현 될 있습니다. 파이썬에서 아이디어를 빌린 것으로 보이는 Icon의 생성기에서와 마찬가지로, 파이썬 생성기에서도 가능합니다. 확실하지는 않지만 F # 이이 트릭을 수행 할 수 있다고 생각합니다. 기본적으로 생성기는 지연 목록을 구현하는 데 적합한 공동 루틴 (예 : 협동 멀티 태스킹)의 특수한 경우입니다. 생성자가 결과를 "수율"할 때마다 호출자는 제어권을 다시 얻고 다음 결과가 요청 될 때까지 생성기가 유휴 상태를 유지합니다.
Steve314

8

재귀는 "분할 및 정복"전략의 형태 또는 "코드 재사용"의 형태이거나, 또는 그 자체의 디자인 패턴입니다.

둘 다. 나누기 및 정복 재귀를 사용합니다 . 그러나 재귀가 문제를 두 개 이상의 부분으로 나누고 각각을 대칭 적으로 해결한다는 것을 의미하기 때문에 재귀가 반드시 분할 및 정복은 아닙니다. 재귀에서는이 작업을 수행하지 않습니다.

코드 재사용은 완전히 관련이 없으며 디자인 패턴이 훨씬 더 높은 수준에서 작동합니다. 예를 들어, 분할 및 정복 (재귀보다 높은 수준의 패턴)조차도 디자인 패턴으로 간주되지 않고 알고리즘 패턴입니다.

재귀가 즉각적인 해결책으로 떠오르는 실제 문제의 예를 들어 주시겠습니까?

나무 통과. 또는 더 일반적으로 그래프 순회. 여기에는 특히 폴더 구조 통과가 포함됩니다.

물론 분할 및 정복 또는 동적 프로그래밍을 사용하는 것은 모두 재귀 측면에서 자연스럽게 표현되기 때문에 물론 입니다.


동적 프로그래밍이 항상 자연스럽게 재귀로 표현되는 것은 아닙니다. 실제로 동적 프로그래밍은 메모를 제외한 테이블 형식의 접근 방식을 엄격하게 참조합니다. 이에 대한 의견은 다양하지만 "동적 프로그래밍"의 "프로그래밍"은 실제로 테이블 형식의 접근 방식 (MIT 오픈 소스웨어 알고리즘 과정에서 얻은 간단한 부분)을 참조하는 수학 용어입니다. 따라서 동적 프로그래밍은 종종 간단한 루프로 가장 쉽게 표현되는 것을 사용하여 최적의 하위 구조를 이용합니다. 메모 화는 재귀를 암시 할 가능성이 훨씬 높지만 반드시 그런 것은 아닙니다.
Steve314

1
@ Steve314 DP의 실제 구현 (컴퓨터 프로그램이든 수동이든)은 재귀를 거의 사용하지 않는다는 데 동의합니다. 그러나이 아이디어 는 본질적으로 재귀 관계를 기반으로합니다. – 기본 사례.
Konrad Rudolph

"최적의 하위 구조"(최적 솔루션에는 최적의 부분 솔루션이 있음)가 재귀 적 아이디어라는 데 동의합니다. 그것은 구현과 직접 관련이없는 재귀에 대한 수학 / 컴퓨터 과학의 관점입니다. 그러나 컴퓨터 과학에서 재귀의 역할은 중요한 포인트입니다. 컴퓨터 과학에서 중요한 도구는 (아마도 디자인 패턴이없는) 알고리즘이 거의 없습니다. 대부분 다른 것을 연구하는 데 사용되는 도구가 아니라 순수하게 연구 대상입니다.
Steve314

4
what are the "problem patterns" that call for the solution of recursion

프랙탈의 자기 유사성에서 파생 된 나는 자기 평등 또는 자기 동일성 (또는 호출)이 재귀에 대한 전형적인 문제 패턴이라고 말한다. 즉, 문제는 주요 문제와 구조가 동일한 하위 문제로 나눌 수 있습니다.

언급 된 트리 탐색에서 각 하위 트리는 기본 트리와 마찬가지로 전체 트리이며 기본 트리는 다른 트리 내의 하위 트리 일 수 있습니다.

그래서 동료가 색인 문제의 자기 평등 속성을 발견했다고 생각합니다. 또는 그는 다른 길로 가서 문제를 자기 평등 한 표현으로 변형했습니다.


1
+1 대해 '문제는 주요한 문제와 똑같은 구조를 갖는 서브 문제로 스플릿 될 수있다 "
treecoder

+1과 패러 프레이즈 : 문제 해결책이 하위 계층에 적용됩니다. 제 실제 사례는 "일괄 처리"에 기여하는 신용 ​​카드 청구를 찾는 것입니다. 회계 소프트웨어는 개별 요금과 당좌 예금으로의 예금을 갖게됩니다. stackoverflow가 그것에 대해 너무 예리하지 않았기 때문에 내 사건은 여기에 의문이 될 수 있습니다. stackoverflow.com/questions/14719806
Chris K

3

명령형 루프를 함수형 함수로 변환하려고하면 재귀를 쉽게 이해할 수 있습니다. 어쨌든 모든 질문에 대한 답변을 해보자.

재귀의 해결을 요구하는 "문제 패턴"은 무엇인가

트리와 같은 구조 또는 알고리즘이 있다면 재귀가 필요합니다. 명령형 코드가 스택을 처리하는 경우 재귀가 필요합니다. 알고리즘의 특정 단계가 이전 단계 (사고 루프)에 의존하는 경우 재귀가 필요합니다. 여기서 필요한 것은 사용 가능한 것으로 해석되어야합니다.

재귀는 "분할 및 정복"전략의 형태 또는 "코드 재사용"의 형태이거나, 또는 그 자체의 디자인 패턴입니다.

없음 나누기와 정복은 재귀를 사용하지만 스택으로 구현할 수 있습니다. 코드 재사용은 다른 것을 의미합니다. 디자인 패턴은 단순한 재귀보다 복잡합니다.

재귀가 즉각적인 해결책으로 떠오르는 실제 문제의 예를 들어 주시겠습니까?

파싱과 트리 구조를 다루는 모든 것. 암시 적 트리 구조조차도.


3

쉽게 단순화 할 수있는 방법이 있다면 재귀가 작동 할 수있는 단서가 될 수 있습니다. 병합 정렬이진 검색 과 같은 재귀 솔루션이있는 예제를 정렬 하고 검색 할 수 있습니다 .

명심해야 할 것은 계승과 같은 재귀로 일부 문제를 제대로 해결할 수 없다는 것입니다.

재귀를 사용하는 실제 예에서 책장에서 책을 찾는 것은 재귀 적으로 매우 쉽게 수행 할 수 있습니다. 나는 단지 책을보고 그것이 내가 원하는 것이 아니라면 다음 책으로 넘어 간다. 책을 찾거나 줄 끝을 쳤을 때 멈 춥니 다. 책을 확인하고 다음 책으로 넘어가는 과정은 반복적으로 이루어질 수 있습니다. 아마도 이것은 실제 사례가 아닙니다.


2

재귀의 해결을 요구하는 "문제 패턴"은 무엇인가

매우 일반적인 용어로, f (x) = f (g (x)) 인 문제를 해결할 때 재귀가 필요합니다 . 무한 재귀에 문제가 없다면 g (x)x로 평가되어서는 안됩니다 .

재귀는 "분할 및 정복"전략의 형태 또는 "코드 재사용"의 형태이거나, 또는 그 자체의 디자인 패턴입니다.

위의 어느 것도 아닙니다. 때로는 입력의 변형을 기반으로 동일한 작업을 반복적으로 수행하는 방법 일뿐입니다. 그 개념은 디자인 패턴, 코드 재사용 또는 심지어 컴퓨터보다 훨씬 오래되었습니다.

재귀가 즉각적인 해결책으로 떠오르는 실제 문제의 예를 들어 주시겠습니까?

계승, 피보나치 수열, 나무 순회 및 기타 여러 가지 문제를 회귀로 해결할 수 있습니다. 함수 호출 자체의 의미에서 재귀가 반드시 그런 종류의 것들을 구현하는 가장 좋은 방법 은 아닙니다 . 더 바람직한 동일한 효과 (예 : 스택 및 루프)를 달성하는 다른 방법이 있습니다.


-1

재귀 알고리즘을 작성할 때 일반적으로 문제 의 재귀 정의 를 코드로 변환합니다. 그러면 어떻게 실행 될지 알 필요조차 없습니다 .

함수형 프로그래밍에서 일어나는 일입니다. 사실, 당신은 지정 무엇을 (정의)보다는 방법 . 다시 말해, 기본을 정의한 다음 하위 문제의 용어로 문제를 정의합니다.

예를 들어 Factorial알고리즘을 고려하십시오

  • 밑을 정의합니다 : Factorial (1) = 1;
  • 계승 정의 n : 계승 (n) = n * 계승 (n-1);

그런 다음 문제가 발생하면 재귀 적으로 정의 할 수 있는지, 재귀 적으로 정의 할 수 있으면 거의 해결했다고 생각해야합니다.

그러나 재귀 함수는 재귀 정의가 아니어야합니다. 기본 문제점을 정의하고 주요 문제점의 솔루션을 하위 문제점의 솔루션 (정의)과 연관 (정의) 할 수 있습니다. 그러나이 관계를 위해서는 절차가 필요할 수 있습니다.

예는 MergeSortmerge정의 또는 서브 - 어레이의 정렬로 전체 어레이를 정렬하는 용액을 연관하는 절차 필수적 일 수있다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.