태그 보관물: recursion

recursion

재귀 또는 while 루프 마쳤습니다. “Ok 루프로 문제를 해결했습니다. 이제 재귀

몇 가지 개발 인터뷰 관행, 특히 인터뷰에서 요청 된 기술 질문 및 테스트에 대해 읽었으며 장르의 말에 대해 몇 번이나 우연히 마쳤습니다. “Ok 루프로 문제를 해결했습니다. 이제 재귀 “또는”모두 100 줄 while 루프로이 문제를 해결할 수 있지만 5 줄 재귀 함수로 해결할 수 있습니까? ” 기타

내 질문은 재귀가 if / while / for 구문보다 일반적으로 더 낫습니까?

솔직히 말해서 재귀는 힙보다 훨씬 작은 스택 메모리로 제한되기 때문에 많은 수의 함수 / 메소드 호출을 수행하는 것이 성능 관점에서 차선책이기 때문에 항상 바람직하지 않다고 생각했습니다. 틀리다 …



답변

재귀는 루프보다 본질적으로 낫거나 나쁘지 않습니다. 각각은 장단점이 있으며 프로그래밍 언어 (및 구현)에 따라 다릅니다.

기술적으로 반복 루프는 하드웨어 수준에서 일반적인 컴퓨터 시스템에 더 잘 맞습니다. 머신 코드 수준에서 루프는 테스트와 조건부 점프에 불과하지만 재귀 (순진하게 구현)는 스택 프레임 푸시, 점프, 리턴 및 팝핑을 포함합니다. 스택에서. OTOH는 스택 푸시 / 팝을 피할 수 있도록 많은 재귀 사례 (특히 반복 루프와 매우 유사한 사례)를 작성할 수 있습니다. 재귀 함수 호출이 리턴하기 전에 함수 본문에서 마지막으로 발생하는 경우 가능하며 일반적으로 테일 호출 최적화 (또는 테일 재귀 최적화 )라고합니다. 적절하게 테일 콜에 최적화 된 재귀 함수는 대부분 머신 코드 레벨의 반복 루프와 동일합니다.

또 다른 고려 사항은 반복 루프에는 파괴적인 상태 업데이트가 필요하므로 순수한 (부작용이없는) 언어 시맨틱과 호환되지 않습니다. 이것이 Haskell과 같은 순수한 언어에 루프 구성이 전혀없는 이유이며, 다른 많은 함수형 프로그래밍 언어에는 완전히 부족하거나 가능한 한 피하는 것이 좋습니다.

인터뷰에서 이러한 질문이 너무 많이 나타나는 이유는 답변하기 위해서는 변수, 함수 호출, 범위 및 물론 루프 및 재귀와 같은 많은 중요한 프로그래밍 개념에 대한 철저한 이해가 필요하기 때문입니다. 두 가지 근본적으로 다른 각도에서 문제에 접근하고 동일한 개념의 다른 표현 사이를 이동할 수있는 정신적 유연성을 테이블에 가져옵니다.

경험과 연구에 따르면 변수, 포인터 및 재귀를 이해할 수있는 능력이있는 사람과 그렇지 않은 사람 사이에는 경계가 있다고합니다. 학습, 경험을 통해 프레임 워크, API, 프로그래밍 언어 및 관련 사례를 포함한 프로그래밍의 거의 모든 것을 얻을 수 있지만이 세 가지 핵심 개념에 대한 직관을 개발할 수없는 경우 프로그래머가되기에 부적합합니다. 간단한 반복 루프를 재귀 버전으로 변환하는 것은 비 프로그래머를 필터링하는 가장 빠른 방법에 관한 것입니다. 숙련되지 않은 프로그래머도 일반적으로 15 분 안에 처리 할 수 ​​있으며 언어에 구애받지 않는 문제이므로 후보자가 선택할 수 있습니다. 특유의 걸림돌 대신 자신이 선택한 언어.

인터뷰에서 이와 같은 질문을한다면 좋은 징조입니다. 예비 고용주는 프로그래밍 도구 매뉴얼을 암기 한 사람들이 아니라 프로그래밍 할 수있는 사람들을 찾고 있음을 의미합니다.


답변

따라 다릅니다.

  • 퀵 정렬과 같은 일부 문제는 재귀 솔루션에 매우 적합합니다.
  • 일부 언어는 재귀를 실제로 지원하지 않습니다 (예 : 초기 FORTRAN)
  • 일부 언어는 재귀를 반복의 기본 수단으로 가정합니다 (예 : Haskell)

꼬리 재귀에 대한 지원 은 꼬리 재귀 및 반복 루프를 동등하게 만듭니다. 즉, 재귀가 항상 스택을 낭비 할 필요는 없습니다.

또한 재귀 알고리즘은 항상 명시 적 스택을 사용하여 반복적으로 구현할 수 있습니다 .

마지막으로 5 라인 솔루션은 아마도 100 라인 솔루션보다 항상 낫습니다 (실제로 동일하다고 가정).


답변

프로그래밍에있어 “더 나은”에 대한 정의는 보편적으로 합의 된 것은 아니지만 “유지 / 읽기 더 쉽다”는 의미로 사용하겠습니다.

재귀는 반복 반복 구조보다 표현력이 뛰어납니다. while 루프는 꼬리 재귀 함수와 동일하고 재귀 함수는 꼬리 재귀가 아니기 때문에 이것을 말합니다. 강력한 구문은 읽기 어려운 작업을 수행 할 수 있기 때문에 일반적으로 나쁜 것입니다. 그러나 재귀는 가변성을 사용하지 않고 루프를 작성할 수있는 기능을 제공하며 내 마음에는 가변성이 재귀보다 훨씬 강력합니다.

따라서 낮은 표현력에서 높은 표현력에 이르기까지 반복 구성은 다음과 같이 쌓입니다.

  • 불변 데이터를 사용하는 테일 재귀 함수,
  • 불변 데이터를 사용하는 재귀 함수
  • 가변 데이터를 사용하는 while 루프
  • 가변 데이터를 사용하는 테일 재귀 함수
  • 가변 데이터를 사용하는 재귀 함수

이상적으로는 표현할 수있는 표현이 가장 적습니다. 물론, 언어가 테일 콜 최적화를 지원하지 않는 경우 루프 구성의 선택에 영향을 줄 수도 있습니다.


답변

재귀는 종종 덜 분명합니다. 덜 명백한 것은 유지하기가 더 어렵다.

당신이 쓰는 경우 for(i=0;i<ITER_LIMIT;i++){somefunction(i);}주요 흐름, 당신은 완벽하게 분명 당신은 루프를 작성합니다. 글을 쓰면 somefunction(ITER_LIMIT);어떤 일이 일어날 지 분명하게 밝히지 않습니다. 내용보기 만 : 그 somefunction(int x)호출 somefunction(x-1)은 실제로 반복을 사용하는 루프 임을 알려줍니다. 또한 break;반복의 어딘가에 이스케이프 조건을 쉽게 넣을 수 없으므로 다시 전달되는 조건을 추가하거나 예외를 throw해야합니다. (그리고 예외는 다시 복잡성을 추가합니다 …)

본질적으로 반복과 재귀 사이의 명백한 선택이라면 직관적 인 일을하십시오. 반복이 작업을 쉽게 수행한다면, 2 줄을 절약하는 것이 장기적으로 발생할 수있는 두통의 가치는 거의 없습니다.

물론 98 줄을 절약한다면 완전히 다른 문제입니다.

재귀가 완벽하게 맞는 상황이 있으며 실제로 드문 일이 아닙니다. 트리 구조, 다중 연결된 네트워크, 자체 유형의 다차원 들쭉날쭉 한 배열을 포함 할 수있는 구조 (기본적으로 간단한 벡터 나 고정 차원의 배열이 아닌 모든 것)의 순회. 알려진 직선 경로를지나 가면 반복하십시오. 알 수없는 상태로 뛰어들었다면 재귀하십시오.

기본적으로 somefunction(x-1)레벨 당 두 번 이상 자체에서 호출해야하는 경우 반복을 잊어 버리십시오.

… 재귀로 가장 잘 수행되는 작업에 대해 반복적으로 기능을 작성하는 것은 가능하지만 즐겁지 않습니다. 사용하는 곳마다 int다음과 같은 것이 필요합니다 stack<int>. 나는 실제적인 목적보다 운동으로 한 번 더했다. 일단 당신이 그런 일에 직면하면 당신이 말한 것과 같은 의심은 없을 것입니다.


답변

평상시와 같이, 이것은 실제로 사례 사이에 광범위하지 않고 유스 케이스 내에서 서로 다른 추가 요소가 있기 때문에 일반적으로 대답 할 수 없습니다. 다음은 몇 가지 압력입니다.

  • 짧고 우아한 코드는 일반적으로 길고 복잡한 코드보다 우수합니다.
  • 그러나 개발자 기반이 재귀에 익숙하지 않고 배우고 싶지 않거나 배우지 못하는 경우 마지막 포인트는 다소 무효화됩니다. 심지어 긍정적이 아닌 약간 부정적 이 될 수도 있습니다 .
  • 실제로 통화가 많이 필요 하고 테일 재귀를 사용할 수 없거나 환경에서 테일 재귀를 최적화 할 수없는 경우 재귀는 효율성이 떨어질 수 있습니다 .
  • 중간 결과를 제대로 캐시 할 수없는 경우 많은 경우 재귀도 좋지 않습니다. 예를 들어, 트리 재귀를 사용하여 피보나치 수를 계산하는 일반적인 예는 캐시하지 않으면 끔찍한 성능을 나타 냅니다. 캐시를 사용하면 간단하고 빠르며 우아하고 훌륭합니다.
  • 재귀는 어떤 경우에는 적용되지 않으며 다른 경우의 반복만큼 우수하고 다른 경우에는 절대적으로 필요합니다. 긴 비즈니스 규칙 체인을 통한 플로팅은 일반적으로 재귀로 전혀 도움이되지 않습니다. 데이터 스트림을 통한 반복은 재귀를 통해 유용하게 수행 할 수 있습니다. 다차원 동적 데이터 구조 (예 : 미로, 객체 트리 등)를 반복하는 것은 재귀, 명시 적 또는 암시 없이는 거의 불가능합니다. 이 경우 명시 적 재귀는 암시 적보다 훨씬 낫습니다. 누군가가 무서운 R- 단어를 피하기 위해 언어 내에서 임의의 불완전하고 버그가있는 스택을 구현 한 코드를 읽는 것보다 더 고통스러운 것은 없습니다.

답변

재귀는 함수 호출을 반복하는 것에 관한 것이고, 루프는 메모리에 배치하기 위해 점프를 반복하는 것에 관한 것입니다.

스택 오버플로에 대해서도 언급해야합니다-http: //en.wikipedia.org/wiki/Stack_overflow


답변

실제로 편의성 또는 요구 사항에 따라 다릅니다.

프로그래밍 언어 Python 을 사용하면 재귀를 지원하지만 기본적으로 재귀 깊이 (1000)에는 제한이 있습니다. 한도를 초과하면 오류 또는 예외가 발생합니다. 이 제한은 변경 될 수 있지만 그렇게하면 언어에 비정상적인 상황이 발생할 수 있습니다.

현재 (재귀 수준보다 많은 호출 수) 루프 구성을 선호해야합니다. 스택 크기가 충분하지 않으면 루프 구조를 선호해야합니다.