재귀에 대해 찾을 수있는 거의 모든 기사에는 다음과 같은 계승 또는 피보나치 수의 예가 포함됩니다.
- 수학
- 실생활에서 쓸모없는
재귀를 가르치는 흥미로운 수학 이외의 코드 예제가 있습니까?
분할 및 정복 알고리즘을 생각하고 있지만 일반적으로 복잡한 데이터 구조가 필요합니다.
재귀에 대해 찾을 수있는 거의 모든 기사에는 다음과 같은 계승 또는 피보나치 수의 예가 포함됩니다.
재귀를 가르치는 흥미로운 수학 이외의 코드 예제가 있습니까?
분할 및 정복 알고리즘을 생각하고 있지만 일반적으로 복잡한 데이터 구조가 필요합니다.
답변:
디렉토리 / 파일 구조는 재귀 사용의 가장 좋은 예입니다. 시작하기 전에 모든 사람들이 이해하지만 트리와 같은 구조와 관련된 모든 것이 가능하기 때문에.
void GetAllFilePaths(Directory dir, List<string> paths)
{
foreach(File file in dir.Files)
{
paths.Add(file.Path);
}
foreach(Directory subdir in dir.Directories)
{
GetAllFilePaths(subdir, paths)
}
}
List<string> GetAllFilePaths(Directory dir)
{
List<string> paths = new List<string>();
GetAllFilePaths(dir, paths);
return paths;
}
나무 구조와 관련된 것을 찾으십시오. 트리는 비교적 이해하기 쉽고 목록과 같은 선형 데이터 구조보다 재귀 솔루션의 아름다움이 훨씬 빨리 나타납니다.
고려해야 할 사항 :
이들은 모두 실제 실제 시나리오와 관련이 있으며 실제 중요 응용 프로그램에서 모두 사용할 수 있습니다.
https://stackoverflow.com/questions/105838/real-world-examples-of-recursion
https://stackoverflow.com/questions/2085834/how-did-you-practically-use-recursion
https://stackoverflow.com/questions/126756/examples-of-recursive-functions
QuickSort는 가장 먼저 떠오르는 것입니다. 이진 검색은 재귀 문제입니다. 그 외에도 재귀 작업을 시작할 때 솔루션이 거의 무료로 빠지는 전체 클래스의 문제가 있습니다.
파이썬에서 재귀 적으로 정의하고 정렬하십시오.
def sort( a ):
if len(a) == 1: return a
part1= sort( a[:len(a)//2] )
part2= sort( a[len(a)//2:] )
return merge( part1, part2 )
재귀 적으로 정의 된 병합
def merge( a, b ):
if len(b) == 0: return a
if len(a) == 0: return b
if a[0] < b[0]:
return [ a[0] ] + merge(a[1:], b)
else:
return [ b[0] ] + merge(a, b[1:])
재귀 적으로 정의 된 선형 검색.
def find( element, sequence ):
if len(sequence) == 0: return False
if element == sequence[0]: return True
return find( element, sequence[1:] )
이진 검색으로 재귀 적으로 정의됩니다.
def binsearch( element, sequence ):
if len(sequence) == 0: return False
mid = len(sequence)//2
if element < mid:
return binsearch( element, sequence[:mid] )
else:
return binsearch( element, sequence[mid:] )
어떤 의미에서 재귀는 솔루션을 나누고 정복하는 것입니다. 즉, 간단한 문제에 대한 해결책을 찾기 위해 문제 공간을 더 작은 문제로 분해 한 다음 원래의 문제를 재구성하여 정답을 작성합니다.
재귀를 가르치기 위해 수학을 포함하지 않는 몇 가지 예 (적어도 대학 시절에 기억했던 문제) :
다음은 역 추적을 사용하여 문제를 해결하는 예입니다.
다른 문제는 인공 지능 영역의 고전입니다. 심층 우선 검색 사용, 길 찾기, 계획.
이러한 모든 문제에는 일종의 "복잡한"데이터 구조가 포함되지만 수학 (숫자)으로 가르치지 않으려면 선택이 더 제한 될 수 있습니다. Yoy는 연결된 List와 같은 기본 데이터 구조로 가르치기를 시작할 수 있습니다. 예를 들어 List를 사용하여 자연수를 나타내는 경우 :
0 = 빈 목록 1 = 하나의 노드가있는 목록 2 = 2 개의 노드가있는 목록 ...
그런 다음이 데이터 구조와 관련하여 두 숫자의 합을 다음과 같이 정의하십시오. Empty + N = N Node (X) + N = Node (X + N)
하노이 타워는 재귀를 배우는 데 도움이되는 좋은 곳입니다.
웹에는 다양한 언어로 된 솔루션이 많이 있습니다.
회문 검출기 :
문자열로 시작 : "ABCDEEDCBA"시작 및 끝 문자가 동일하면 되풀이하고 "BCDEEDCB"등을 확인하십시오.
이진 검색 알고리즘은 원하는 것 같습니다.
함수형 프로그래밍 언어에서 고차 함수를 사용할 수없는 경우 변경 가능한 상태를 피하기 위해 명령형 루프 대신 재귀가 사용됩니다.
F #은 두 가지 스타일을 모두 허용하는 불완전한 기능 언어이므로 여기서 두 가지를 비교하겠습니다. 다음은 목록의 모든 숫자를 합한 것입니다.
가변 변수가있는 명령 루프
let xlist = [1;2;3;4;5;6;7;8;9;10]
let mutable sum = 0
for x in xlist do
sum <- sum + x
가변 상태가없는 재귀 루프
let xlist = [1;2;3;4;5;6;7;8;9;10]
let rec loop sum xlist =
match xlist with
| [] -> sum
| x::xlist -> loop (sum + x) xlist
let sum = loop 0 xlist
이러한 종류의 집계 는 고차 함수에서 캡처되며 편의 함수 를 사용하여 훨씬 간단하게 List.fold
작성할 수 있습니다 .List.fold (+) 0 xlist
List.sum
List.sum xlist
나는 AI를 플레이하는 게임에서 재귀를 많이 사용했습니다. C ++로 작성하면 서로를 순서대로 호출하는 약 7 개의 함수 시리즈를 사용했습니다 (첫 번째 함수는 모든 함수를 무시하고 대신 2 개의 함수 체인을 호출하는 옵션이 있음). 검색하려는 나머지 깊이가 0이 될 때까지 두 체인의 최종 함수가 첫 번째 함수를 다시 호출했습니다.이 경우 최종 함수는 내 평가 함수를 호출하고 위치 점수를 반환합니다.
여러 기능을 통해 플레이어의 결정 또는 게임의 임의 이벤트를 기반으로 쉽게 분기 할 수있었습니다. 매우 큰 데이터 구조를 전달하고 있었지만 게임 구조 방식으로 인해 검색에서 "실행 취소"를 수행하는 것이 매우 어려웠 기 때문에 가능할 때마다 참조 별 전달을 사용했습니다. 원래 데이터를 변경하지 않으려면 일부 함수에서 값별 전달을 사용합니다. 이 때문에 재귀 적 접근 방식 대신 루프 기반 접근 방식으로 전환하는 것이 너무 어려웠습니다.
이러한 종류의 프로그램에 대한 매우 기본적인 개요는 https://secure.wikimedia.org/wikipedia/ko/wiki/Minimax#Pseudocode를 참조 하십시오.
비즈니스에서 실제로 좋은 실례는 "Bill of Materials"입니다. 이것은 완제품을 구성하는 모든 구성 요소를 나타내는 데이터입니다. 예를 들어 자전거를 사용합시다. 자전거에는 핸들 바, 바퀴, 프레임 등이 있으며 각 구성 요소에는 하위 구성 요소가있을 수 있습니다. 예를 들어 휠에는 스포크, 밸브 스템 등이있을 수 있습니다. 따라서 일반적으로 트리 구조로 표시됩니다.
이제 BOM에 대한 집계 정보를 쿼리하거나 BOM의 요소를 변경하기 위해 종종 재귀에 의존합니다.
class BomPart
{
public string PartNumber { get; set; }
public string Desription { get; set; }
public int Quantity { get; set; }
public bool Plastic { get; set; }
public List<BomPart> Components = new List<BomPart>();
}
그리고 샘플 재귀 호출 ...
static int ComponentCount(BomPart part)
{
int subCount = 0;
foreach(BomPart p in part.Components)
subCount += ComponentCount(p);
return part.Quantity * Math.Max(1,subCount);
}
분명히 BomPart 클래스에는 더 많은 필드가 있습니다. 당신은 당신이 가지고있는 플라스틱 부품의 수, 완전한 부품을 만들기 위해 얼마나 많은 노동력이 필요한지 등을 알아 내야 할 수도 있습니다.이 모든 것이 나무 구조에서 재귀의 유용성으로 돌아옵니다.
가족 관계는 모두가 직관적으로 이해하기 때문에 좋은 모범을 보입니다.
ancestor(joe, me) = (joe == me)
OR ancestor(joe, me.father)
OR ancestor(joe, me.mother);
||
에 대한 OR
.
재귀 프로그램을 사용하여 기사 패턴 (체스 보드)의 문제를 해결했습니다. 기사는 몇 개의 표시된 사각형을 제외한 모든 사각형에 닿도록 기사를 움직여야했습니다.
당신은 단순히 :
mark your "Current" square
gather a list of free squares that are valid moves
are there no valid moves?
are all squares marked?
you win!
for each free square
recurse!
clear the mark on your current square.
return.
이와 같은 트리에서 미래의 가능성을 테스트함으로써 많은 종류의 "생각"시나리오를 수행 할 수 있습니다.