재귀에 대한 아이디어는 실제 세계에서는 흔하지 않습니다. 따라서 초보자 프로그래머에게는 약간 혼란 스럽습니다. 비록 그것들이 점차 개념에 익숙해 졌다고 생각합니다. 그렇다면 아이디어를 쉽게 파악할 수있는 좋은 설명은 무엇입니까?
재귀에 대한 아이디어는 실제 세계에서는 흔하지 않습니다. 따라서 초보자 프로그래머에게는 약간 혼란 스럽습니다. 비록 그것들이 점차 개념에 익숙해 졌다고 생각합니다. 그렇다면 아이디어를 쉽게 파악할 수있는 좋은 설명은 무엇입니까?
답변:
재귀 를 설명하기 위해 다른 설명을 조합하여 일반적으로 두 가지 모두 시도합니다.
우선, Wolfram | Alpha 는 Wikipedia 보다 더 간단한 용어로 정의합니다 .
특정 수학 연산을 반복하여 각 항을 생성하는 표현입니다.
학생 (또는 지금부터 설명하는 사람, 지금부터 학생이라고 말할 것입니다)이 적어도 수학적 배경을 가지고 있다면, 시리즈와 재귀 및 재발 관계에 대한 개념을 연구함으로써 이미 재귀에 직면했습니다 .
시작하는 가장 좋은 방법은 시리즈로 시연하고 재귀가 무엇인지 간단히 말해주는 것입니다.
일반적으로, 그들은 여전히 그것을 사용하지 않기 때문에 "허허, whatev '"를 얻거나, 아마도 아주 깊은 코를 likely 수도 있습니다.
나머지 부분은 실제로 포인터에 관해 지적한 질문에 대한 내 답변 의 부록 에 나와있는 내용의 자세한 버전입니다 (나쁜 말장난).
이 단계에서 학생들은 일반적으로 화면에 무언가를 인쇄하는 방법을 알고 있습니다. 우리는 C를 사용하는 가정, 그들은 사용하여 하나의 문자를 인쇄하는 방법을 알고 write
나 printf
. 또한 제어 루프에 대해서도 알고 있습니다.
나는 보통 그들이 얻을 때까지 몇 가지 반복적이고 간단한 프로그래밍 문제에 의지한다.
계승
계승은 이해하기 매우 간단한 수학 개념이며 구현은 수학적 표현에 매우 가깝습니다. 그러나 그들은 처음에는 그것을 얻지 못할 수 있습니다.
알파벳
알파벳 버전은 재귀 진술의 순서에 대해 생각하도록 가르치는 것이 흥미 롭습니다. 포인터와 마찬가지로, 그들은 당신에게 무작위로 줄을 던질 것입니다. 요점은 루프는 조건을 수정하거나 반전 할 수있는 실현에 그들을 데리고하는 것입니다 또는 당신의 함수에서 문장의 순서를 반전. 그것이 시각적으로 보여주기 때문에 알파벳 인쇄가 도움이되는 곳입니다. 각 호출마다 하나의 문자를 인쇄하고 다음 (또는 이전) 문자를 작성하기 위해 재귀 적으로 호출하는 함수를 작성하게하십시오.
FP 팬 여러분, 출력 스트림에 물건을 인쇄하는 것이 현재 부작용이라는 사실을 건너 뛰십시오. FP-front에서 너무 성가 시게하지 마십시오. (하지만리스트 지원 언어를 사용하는 경우, 각 반복마다리스트에 연결하여 최종 결과를 인쇄하십시오. 그러나 일반적으로 C로 시작합니다. 불행히도 이런 종류의 문제와 개념에는 적합하지 않습니다.) .
지수화
지수화 문제는 약간 더 어렵다 ( 이 학습 단계 에서). 분명히 개념은 계승에 대한 개념과 동일하며 여러 매개 변수가 있다는 점을 제외하고는 복잡성이 추가되지 않습니다. 그리고 그것은 보통 사람들을 혼동하고 처음에 그들을 버릴 정도로 충분합니다.
간단한 형태 :
반복해서 다음과 같이 표현할 수 있습니다.
더 세게
이 간단한 문제가 튜토리얼에서 보여지고 다시 구현되면 약간 더 어려운 (그러나 매우 고전적인) 연습을 할 수 있습니다.
참고 : 다시 말하지만,이 중 일부는 더 이상 어렵지 않습니다 ... 그들은 정확히 같은 각도 또는 약간 다른 각도에서 문제에 접근합니다. 그러나 연습은 완벽합니다.
참조
일부 독서는 결코 아프지 않습니다. 글쎄요, 처음에는 더 잃어 버릴 것입니다. 그것은 당신에게서 자라며 언젠가 당신이 마침내 그것을 얻는다는 것을 깨달을 때까지 머리 뒤에 앉아있는 것입니다. 그리고 당신은 당신이 읽은 것들을 다시 생각합니다. 재귀 , 컴퓨터 과학 재귀 및 재발 관계 위키 백과의 페이지가 지금 할 것입니다.
레벨 / 깊이
학생들이 코딩 경험이 많지 않다고 가정하면 코드 스텁을 제공하십시오. 처음 시도한 후에 재귀 수준을 표시 할 수있는 인쇄 기능을 제공하십시오. 레벨의 숫자 값을 인쇄하면 도움이됩니다.
서랍으로 쌓기 다이어그램
인쇄 된 결과 (또는 레벨의 출력)를 들여 쓰면 프로그램이 수행하는 작업, 서랍이나 파일 시스템 탐색기의 폴더와 같은 스택 컨텍스트를 열고 닫는 다른 시각적 표현을 제공하므로 도움이됩니다.
재귀 약어
학생이 이미 컴퓨터 문화에 정통한 경우 재귀 약어를 사용하여 이름이있는 일부 프로젝트 / 소프트웨어를 이미 사용하고있을 수 있습니다 . 오랜 시간 동안, 특히 GNU 프로젝트에서 전통이되었습니다. 몇 가지 예는 다음과 같습니다.
재귀 :
상호 재귀 :
그들에게 스스로 생각해 보라고한다.
마찬가지로 Google의 재귀 검색 수정 과 같이 재귀 유머가 많이 발생 합니다. 재귀에 대한 자세한 내용은이 답변을 읽으십시오 .
사람들이 일반적으로 어려움을 겪고 답변을 알아야하는 일부 문제.
왜, 오 하나님 왜 ???
왜 그렇게 하시겠습니까? 좋고 분명하지 않은 이유는 종종 그런 식으로 문제를 표현하는 것이 더 간단하다는 것입니다. 좋지는 않지만 명백한 이유는 타이핑이 덜 필요하다는 것입니다 (재귀를 사용한다고해서 soooo l33t를 느끼게하지 마십시오 ...).
재귀 접근 방식을 사용할 때 일부 문제를 해결하기가 훨씬 쉽습니다. 일반적으로 Divide and Conquer 패러다임을 사용하여 해결할 수있는 모든 문제 는 다중 분기 재귀 알고리즘에 적합합니다.
N은 또 뭐지 ??
n
매번 왜 또는 (변수 이름이 다름) 다른가요? 초보자는 일반적으로 변수와 매개 변수가 무엇인지 이해하는 데 문제가 있으며 n
프로그램에서 이름이 지정된 항목 이 다른 값을 가질 수 있습니다. 이제이 값이 제어 루프 나 재귀에 있으면 훨씬 더 나빠집니다! 훌륭하고 어디에서나 동일한 변수 이름을 사용하지 말고 매개 변수가 변수 라는 것을 분명히 하십시오 .
최종 조건
종료 조건을 어떻게 확인합니까? 간단합니다. 발걸음을 크게 내딛게하십시오. 예를 들어 계승 시작의 경우 5, 4, 그 다음에 0까지.
악마는 세부 사항에 있습니다
테일 콜 최적화 와 같은 초기 접견에 대해서는 이야기하지 마십시오 . TCO는 훌륭하지만 처음에는 신경 쓰지 않습니다. 그들에게 효과가있는 방식으로 머리를 감쌀 시간을 준다. 나중에 다시 세상을 산산조각 낸 다음 휴식을 취하십시오.
마찬가지로, 첫 번째 강의에서 콜 스택 과 메모리 소비 에 대해 이야기하지 마십시오 . 스택 오버플로 . 나는 종종 이 단계에서 정확하게 루프를 거의 쓸 수 없을 때 재귀에 관해 알아야 할 모든 것에 대해 50 개의 슬라이드가있는 강의를 보여주는 사적으로 학생들을지도합니다 . 이것은 참조가 나중에 도움이 될 수있는 좋은 예 이지만 지금 당장 당신을 깊이 혼란스럽게 합니다.
그러나 적절한시기에 반복 또는 재귀 경로를 사용해야 할 이유 가 있음을 분명히 하십시오 .
상호 재귀
우리는 함수가 재귀적일 수 있고 심지어 여러 호출 포인트 (8- 여왕, 하노이, 피보나치 또는 심지어 지뢰 찾기를위한 탐색 알고리즘)를 가질 수 있음을 보았습니다. 그러나 상호 재귀 호출은 어떻습니까? 여기에서 수학부터 시작하십시오. f(x) = g(x) + h(x)
어디 g(x) = f(x) + l(x)
에서 h
그리고 l
그냥 물건을하십시오.
수학 시리즈만으로 시작하면 계약이 표현식으로 명확하게 정의되므로 작성 및 구현이 더 쉬워집니다. 예를 들어, Hofstadter 여성 및 남성 서열 :
그러나 코드 측면에서, 상호 재귀 솔루션의 구현은 종종 코드 복제로 이어지고 단일 재귀 양식으로 간소화되어야합니다 ( Peter Norvig 의 모든 스도쿠 퍼즐 풀기 참조) .
static unsigned int vote = 1;
나에게서 얻는다 . 만약 당신이 원한다면 정적 유머를 용서하십시오 :) 이것은 지금까지 가장 좋은 대답입니다.
사용 방법, 사용시기 및 나쁜 디자인을 피하는 방법을 알아야합니다.
당신이 알아야 할 가장 중요한 것은 결코 끝나지 않는 루프를 얻지 않도록 매우 조심하는 것입니다. pramodc84 에서 귀하의 질문에 대한 답변은 다음과 같은 결함이 있습니다. 결코 끝나지 않습니다 ...
재귀 함수는 항상 자신을 다시 호출 해야하는지 여부를 결정하는 조건을 확인해야합니다.
재귀를 사용하는 가장 전형적인 예는 깊이가 정적 인 제한이없는 트리를 사용하는 것입니다. 이것은 재귀를 사용해야하는 작업입니다.
a
여전히을 호출 하여 간접적으로 호출 b
합니다.
재귀 프로그래밍은 자체 버전을보다 쉽게 해결하기 위해 점진적으로 문제를 줄이는 프로세스입니다.
모든 재귀 함수는 다음과 같은 경향이 있습니다.
2 단계가 3 이전이고 4 단계가 사소한 경우 (연결, 합 또는 기타)에는 꼬리 재귀가 가능 합니다. 현재 단계를 완료하기 위해 문제의 서브 도메인 (들)의 결과가 필요할 수 있으므로 2 단계는 종종 3 단계 이후에 와야합니다.
이진 트리를 순회합니다. 순회는 필요한 항목에 따라 선주문, 주문 또는 주문으로 이루어질 수 있습니다.
B
A C
선주문 : BAC
traverse(tree):
visit the node
traverse(left)
traverse(right)
순서 : ABC
traverse(tree):
traverse(left)
visit the node
traverse(right)
주문 후 : ACB
traverse(tree):
traverse(left)
traverse(right)
visit the node
매우 많은 재귀 문제는 맵 작업 의 특정 사례 또는 접힘입니다. 이 두 작업 만 이해하면 재귀에 대한 유용한 사용 사례를 크게 이해할 수 있습니다.
OP는 재귀가 현실 세계에 존재하지 않는다고 말했지만 나는달라고 간청합니다.
피자를 자르는 실제 '동작'을 보자. 피자를 오븐에서 꺼낸 후 서빙하려면 반으로 자른 다음 반을 자른 다음 다시 반으로 자르십시오.
원하는 결과 (슬라이스 수)를 얻을 때까지 반복해서 수행하는 피자를 자르는 작업입니다. 그리고 논쟁을 위해 자르지 않은 피자는 조각 자체라고 가정 해 봅시다.
다음은 Ruby의 예입니다.
데프 컷 _ 피자 (기존 _ 슬라이스, 원하는 _ 슬라이스) existing_slices! = desired_slices 인 경우 # 우리는 아직 모든 사람에게 먹이를 줄 수있는 슬라이스가 충분하지 않습니다. # 피자 조각을 자르고있어 그 수가 두배가되었습니다 new_slices = 기존 _ 슬라이스 * 2 # 그리고 이것은 재귀 호출입니다. cut_pizza (새 슬라이스, 원하는 슬라이스) 그밖에 # 원하는 슬라이스 수를 가지고 있으므로 # 계속 재귀하는 대신 여기에 existing_slices를 반환 종료 종료 피자 = 1 # 전체 피자, '한 조각' cut_pizza (pizza, 8) # => 8을 얻습니다
따라서 실제 작업은 피자를 자르는 것이며 재귀는 원하는 것을 가질 때까지 반복해서 똑같은 일을하고 있습니다.
재귀 함수로 구현할 수있는 정리는 다음과 같습니다.
파일 이름을 기준으로 파일을 찾도록 프로그램을 작성하고 파일이 발견 될 때까지 자신을 호출하는 함수를 작성하는 것이 좋습니다. 서명은 다음과 같습니다.
find_file_by_name(file_name_we_are_looking_for, path_to_look_in)
따라서 다음과 같이 호출 할 수 있습니다.
find_file_by_name('httpd.conf', '/etc') # damn it i can never find apache's conf
내 의견으로는 단순히 기계 역학을 프로그래밍하는 것입니다. 변수를 사용하여 이것을 다시 작성할 수 있지만 이것은 '더 나은'솔루션입니다. 그것에 대해 신비하거나 어려운 것은 없습니다. 몇 가지 재귀 함수를 작성하면 프로그래밍 도구 상자에서 또 다른 기계적 트릭을 클릭하고 huzzah 합니다.
추가 크레디트cut_pizza
위 의 예는 2의 거듭 제곱 (예 : 2 또는 4 또는 8 또는 16)이 아닌 여러 조각을 요청하면 스택 수준에 너무 큰 오류가 발생합니다. 누군가 10 조각을 요청하면 영원히 실행되지 않도록 수정할 수 있습니까?
좋아, 나는 이것을 간단하고 간결하게 유지하려고 노력할 것이다.
재귀 함수는 자신을 호출하는 함수입니다. 재귀 함수는 다음 세 가지로 구성됩니다.
재귀 메서드를 작성하는 가장 좋은 방법은 반복하려는 프로세스의 한 루프 만 처리하는 간단한 예제로 작성하려는 메서드를 생각한 다음 메서드 자체에 호출을 추가하고 원하는 때 추가하는 것입니다. 끝내다. 배우는 가장 좋은 방법은 모든 것처럼 연습하는 것입니다.
이것은 프로그래머 웹 사이트이므로 코드 작성을 자제하지만 여기에 좋은 링크가 있습니다.
농담을하면 재귀의 의미를 알 수 있습니다.
재귀는 프로그래머가 자체적으로 함수 호출을 호출하는 데 사용할 수있는 도구입니다. 피보나치 수열은 재귀 사용 방법의 교과서 예입니다.
대부분의 재귀 코드는 모두 반복 함수로 표현할 수는 없지만 일반적으로 지저분합니다. 다른 재귀 프로그램의 좋은 예는 트리, 이진 검색 트리 및 퀵 정렬과 같은 데이터 구조입니다.
재귀는 코드를 느슨하게 만드는 데 사용되며 일반적으로 속도가 느리고 더 많은 메모리가 필요합니다.
나는 이것을 사용하고 싶다 :
상점 입구에 있다면 간단히 살펴보십시오. 그렇지 않으면 한 걸음 내딛고 나머지 길을 가게로 걸어가십시오.
세 가지 측면을 포함하는 것이 중요합니다.
우리는 실제로 일상 생활에서 재귀를 많이 사용합니다. 우리는 그렇게 생각하지 않습니다.
for
루프를 무의미한 재귀 함수로 변환하는 것과 같습니다 .
Josh K는 이미 Matroshka 인형을 언급했습니다 . 가장 짧은 인형 만이 아는 것을 배우고 싶다고 가정하십시오. 문제는 그녀가 원래 첫 번째 그림의 왼쪽에있는 키가 큰 인형 안에 살고 있기 때문에 직접 대화 할 수 없다는 것 입니다. 이 구조는 가장 큰 인형으로 끝날 때까지 (인형은 더 큰 인형 안에 살고 있습니다).
그래서 당신이 할 수있는 유일한 것은 가장 큰 인형에게 질문을하는 것입니다. 가장 큰 인형 (답변을 모르는 사람)은 질문을 더 짧은 인형 (첫 번째 그림의 오른쪽에 있음)으로 전달해야합니다. 그녀는 또한 대답이 없기 때문에 다음으로 짧은 인형에게 물어볼 필요가 있습니다. 메시지가 가장 짧은 인형에 도달 할 때까지 이렇게됩니다. 가장 짧은 인형 (비밀 답변을 아는 유일한 사람)은 다음 키 큰 인형 (왼쪽에 있음)으로 답을 전달하고 다음 키 큰 인형에게 전달합니다. 가장 큰 인형 인 최종 목적지에 도달하고 마침내 ... you :)
이것이 재귀가 실제로하는 일입니다. 함수 / 메소드는 예상되는 답변을 얻을 때까지 자신을 호출합니다. 따라서 재귀 코드를 작성할 때 재귀 종료 시점을 결정하는 것이 매우 중요합니다.
가장 좋은 설명은 아니지만 희망적으로 도움이됩니다.
재귀 n. -연산이 자체적으로 정의되는 알고리즘 설계 패턴.
전형적인 예는 숫자 n의 계승을 찾는 것입니다. 0! = 1이고 다른 자연수 N의 경우 N의 계승은 N보다 작거나 같은 모든 자연수의 곱입니다. 따라서 6! = 6 * 5 * 4 * 3 * 2 * 1 = 720.이 기본 정의를 사용하면 간단한 반복 솔루션을 만들 수 있습니다.
int Fact(int degree)
{
int result = 1;
for(int i=degree; i>1; i--)
result *= i;
return result;
}
그러나 작업을 다시 점검하십시오. 6! = 6 * 5 * 4 * 3 * 2 * 1. 같은 정의로 5! = 5 * 4 * 3 * 2 * 1, 6이라고 말할 수 있습니다! = 6 * (5!). 차례로 5! = 5 * (4!) 등. 이렇게하면 모든 이전 작업의 결과에 대해 수행 된 작업으로 문제가 줄어 듭니다. 결국 결과는 정의에 의해 알려진 기본 사례라고하는 지점으로 줄어 듭니다. 이 경우 0! = 1 (대부분의 경우 1! = 1이라고도 함). 컴퓨팅에서 우리는 종종 메소드 호출 자체를 통해 더 작은 입력을 전달함으로써 매우 유사한 방식으로 알고리즘을 정의 할 수 있습니다. 따라서 많은 재귀를 통한 문제를 기본 사례로 줄입니다.
int Fact(int degree)
{
if(degree==0) return 1; //the base case; 0! = 1 by definition
else return degree * Fact(degree -1); //the recursive case; N! = N*(N-1)!
}
많은 언어에서 삼항 연산자를 사용하여 더 단순화 할 수 있습니다 (때로는 연산자를 제공하지 않는 언어에서는 Iif 함수로 표시됨).
int Fact(int degree)
{
//reads equivalently to the above, but is concise and often optimizable
return degree==0 ? 1: degree * Fact(degree -1);
}
장점 :
단점 :
내가 사용하는 예는 실생활에서 직면 한 문제입니다. 컨테이너 (여행용 대형 배낭 등)가 있으며 총 무게를 알고 싶습니다. 용기에 2 ~ 3 개의 느슨한 품목과 다른 용기 (예 : 재료 자루)가 있습니다. 총 용기의 무게는 분명히 빈 용기의 무게와 그 안에 들어있는 모든 것의 무게를 합한 것입니다. 느슨한 품목의 경우 무게를 측정 할 수 있으며, 재료 자루의 경우 무게를 측정하거나 "각 포장의 무게는 빈 용기의 무게와 그 안에 들어있는 모든 것의 무게입니다"라고 말할 수 있습니다. 그런 다음 컨테이너에 항목이 느슨한 지점에 도달 할 때까지 컨테이너에 컨테이너 등을 계속 넣습니다. 재귀입니다.
실생활에서는 결코 일어나지 않는다고 생각할 수도 있지만 특정 회사 나 부서의 직원 수를 계산하거나 합산하면 회사를 위해 일하는 사람들과 부서의 사람들이 혼합되어 있습니다. 부서 등이 있습니다. 또는 지역이 있고 일부 지역에 지역 등이있는 국가에서의 판매. 이런 종류의 문제는 비즈니스에서 항상 발생합니다.
재귀는 많은 계산 문제를 해결하는 데 사용될 수 있습니다. 예를 들어, 파티에 n 명 그룹이 있고 (n> 1) 모든 사람이 다른 사람의 손을 정확히 한 번 흔든다 고 가정합니다. 악수는 몇 번이나됩니까? 솔루션이 C (n, 2) = n (n-1) / 2임을 알 수 있지만 다음과 같이 재귀 적으로 해결할 수 있습니다.
두 사람 만 있다고 가정합니다. 그런 다음 (검사하여) 대답은 분명히 1입니다.
세 사람이 있다고 가정합니다. 한 사람을 골라 내고 다른 두 사람과 악수한다는 점에 유의하십시오. 그 후에는 다른 두 사람 간의 핸드 셰이크 만 계산해야합니다. 우리는 이미 그것을 지금 당장했고 그것은 1입니다. 그래서 답은 2 + 1 = 3입니다.
n 명이 있다고 가정하십시오. 이전과 동일한 논리에 따라 (n-1) + (n-1 명의 핸드 셰이크 수)입니다. 확장하면 (n-1) + (n-2) + ... + 1이됩니다.
재귀 함수로 표현
f (2) = 1
f (n) = n-1 + f (n-1), n> 2
인생에서 (컴퓨터 프로그램과는 달리) 재귀는 우리의 직접적인 통제하에 거의 일어나지 않습니다. 왜냐하면 혼란 스럽기 때문입니다. 또한 인식은 기능적으로 순수하지 않고 부작용에 관한 경향이 있으므로 재귀가 발생하면 인식하지 못할 수 있습니다.
그러나 세계에서는 재귀가 발생합니다. 많이.
좋은 예는 물 순환의 단순화 된 버전입니다.
이것은 다시 발생하게하는주기입니다. 재귀 적입니다.
재귀를 얻을 수있는 또 다른 장소는 영어 (일반적으로 사람의 언어)입니다. 처음에는 그것을 인식하지 못할 수도 있지만, 문장을 생성 할 수있는 방법은 재귀 적입니다. 규칙을 통해 하나의 심볼 인스턴스를 동일한 심볼의 다른 인스턴스와 나란히 포함 할 수 있기 때문입니다.
Steven Pinker의 언어 본능 :
소녀가 아이스크림을 먹거나 소녀가 사탕을 먹는다면 소년은 핫도그를 먹는다
그것은 다른 전체 문장을 포함하는 전체 문장입니다.
여자 아이가 아이스크림을 먹는다
여자 아이가 사탕을 먹는다
소년은 핫도그를 먹는다
완전한 문장을 이해하는 행위에는 작은 문장을 이해하는 것이 포함되는데, 작은 문장은 동일한 문장을 사용하여 완전한 문장으로 이해됩니다.
프로그래밍 관점에서 재귀를 이해하려면 재귀로 해결할 수있는 문제를 살펴보고 그 이유와 그 의미를 이해하는 것이 가장 쉽습니다.
예를 들어, 나는 가장 큰 공통 제수 함수 또는 짧게는 gcd를 사용합니다.
당신은 당신의 두 숫자를 가지고 a
와 b
. 그들의 gcd를 찾으려면 (0이 아닌 것으로 가정) a
로 균등하게 나눌 수 있는지 확인해야합니다 b
. 그것이 b
gcd 인 경우, 그렇지 않으면의 gcd b
및 나머지 를 확인해야합니다 a/b
.
gcd 함수가 gcd 함수를 호출하므로이 함수가 재귀 함수임을 이미 알 수 있습니다. 집으로 망치기 위해 여기에 c #이 있습니다 (다시 말하면 0이 매개 변수로 전달되지 않는다고 가정).
int gcd(int a, int b)
{
if (a % b == 0) //this is a stopping condition
{
return b;
}
return (gcd(b, a % b)); //the call to gcd here makes this function recursive
}
프로그램에서 중지 조건을 갖는 것이 중요합니다. 그렇지 않으면 함수가 영원히 반복되어 결국 스택 오버플로가 발생합니다!
while 루프 나 다른 반복 구조가 아닌 재귀를 사용하는 이유는 코드를 읽을 때 수행중인 작업과 수행 할 작업을 알려주기 때문에 올바르게 작동하는지 파악하기가 더 쉽기 때문입니다. .
다음은 재귀에 대한 실제 예입니다.
그들이 코믹한 컬렉션을 가지고 있다고 상상해 보도록하자. 조심하십시오-실제로 컬렉션이 있으면 아이디어를 언급했을 때 즉시 죽일 수 있습니다.
이제이 매뉴얼의 도움을 받아이 분류되지 않은 큰 만화 더미를 정렬 해 보자.
Manual: How to sort a pile of comics
Check the pile if it is already sorted. If it is, then done.
As long as there are comics in the pile, put each one on another pile,
ordered from left to right in ascending order:
If your current pile contains different comics, pile them by comic.
If not and your current pile contains different years, pile them by year.
If not and your current pile contains different tenth digits, pile them
by this digit: Issue 1 to 9, 10 to 19, and so on.
If not then "pile" them by issue number.
Refer to the "Manual: How to sort a pile of comics" to separately sort each
of the new piles.
Collect the piles back to a big pile from left to right.
Done.
여기서 가장 좋은 점은 단일 이슈에 해당 할 때 로컬 더미가 바닥에 보이도록 전체 "스택 프레임"을 갖습니다. 그들에게 매뉴얼의 여러 인쇄물을 제공하고 현재이 레벨에있는 마크 (예 : 지역 변수의 상태)와 함께 각 더미 레벨을 하나씩 옆에 두십시오. 따라서 각 완료에서 계속할 수 있습니다.
그것은 재귀가 기본적으로하는 것입니다. 아주 세부적인 수준에서 더 똑같은 과정을 수행하는 것입니다.
재귀에 대한 훌륭한 설명은 말 그대로 '자체 내에서 재발하는 행동'입니다.
벽을 그리는 화가를 생각해보십시오. 행동은 "오른쪽으로 스쿠 트하는 것보다 천장에서 바닥으로 스트립을 페인트하고 (오른쪽으로 스쿠 트하는 것보다 천장에서 바닥으로 스트립을 페인트하고) 오른쪽에서 조금 튀기지 말고 천장에서 바닥으로 스트리핑하십시오.
그의 paint () 함수는 자신의 더 큰 paint_wall () 함수를 구성하기 위해 계속해서 자신을 호출합니다.
잘만되면이 가난한 화가는 어떤 종류의 정지 조건이 있습니다 :)