source

비전문가의 용어로는 PHP를 사용한 재귀 함수입니다.

lovecheck 2022. 12. 18. 08:43
반응형

비전문가의 용어로는 PHP를 사용한 재귀 함수입니다.

(Fibonacci를 사용하지 않고) PHP로 재귀 함수를 평신도 언어와 예를 사용하여 설명해 주실 수 있습니까?내가 예를 보고 있었는데 피보나찌가 날 완전히 놓쳤어!

잘 부탁드립니다.-) 또한 웹 개발에서 얼마나 자주 사용하시나요?

일반 용어:

재귀 함수는 자신을 호출하는 함수입니다.

좀 더 상세하게:

함수가 자신을 계속 호출할 경우 언제 정지해야 하는지 어떻게 알 수 있습니까?기본 케이스라고 하는 조건을 설정합니다.베이스 케이스는 재귀 콜의 정지 타이밍을 나타냅니다.정지하지 않으면 무한 루프 상태가 됩니다.

수학에 강한 배경을 가지고 있기 때문에 나에게 좋은 학습 예는 요인이다.아래 코멘트로 보면, 요인 함수는 조금 무리인 것 같기 때문에, 만약을 위해 여기에 남겨 두겠습니다.

function fact($n) {
  if ($n === 0) { // our base case
     return 1;
  }
  else {
     return $n * fact($n-1); // <--calling itself.
  }
}

Web 개발에서의 재귀 함수 사용에 대해서는, 개인적으로 재귀 콜의 사용에 의지하고 있지 않습니다.재귀에 의존하는 것이 나쁜 관행이라고 생각하는 건 아니지만, 재귀가 당신의 첫 번째 선택이 되어서는 안 됩니다.제대로 사용하지 않으면 치명적일 수 있습니다.

디렉토리 예시와 경쟁할 수는 없지만, 어느 정도 도움이 되었으면 합니다.

(4/20/10) 갱신:

또한 이 질문을 체크하는 것도 도움이 될 것입니다.여기서 받아들여진 답변은 재귀함수가 어떻게 작용하는지 평신도의 용어로 보여줍니다.OP의 질문은 Java를 다루었지만 개념은 동일합니다.

예를 들어 지정된 디렉터리의 하위 디렉터리에 있는 모든 파일을 인쇄할 수 있습니다(이 디렉터리 내에 심볼 링크가 없는 경우 기능이 중단될 수 있음).모든 파일을 인쇄하는 의사 코드는 다음과 같습니다.

function printAllFiles($dir) {
    foreach (getAllDirectories($dir) as $f) {
        printAllFiles($f); // here is the recursive call
    }
    foreach (getAllFiles($dir) as $f) {
        echo $f;
    }
}

우선 모든 서브 디렉토리를 인쇄하고 다음으로 현재 디렉토리의 파일을 인쇄합니다.이 아이디어는 모든 서브디렉토리에 적용되기 때문에 모든 서브디렉토리에서 이 함수를 재귀적으로 호출합니다.

, 「」를 체크할 필요가 .. ★★★★★★★★★★★★★★★★★」..할 수 printAllFiles(".")또한 인쇄하는 해야 합니다( 참조).opendir(),getcwd() ) , ... ) 。

재귀는 반복되는 것입니다.마치 내부에서 자신을 부르는 기능처럼요몇 가지 유사 예를 들어 설명하겠습니다.

친구들과 맥주를 마시며 외출 중인데 자정 전에 집에 오지 않으면 아내가 혼낼 거라고 상상해 보세요.이를 위해 order And Drink Beer($time) 함수를 만듭니다.여기서 $time은 자정에서 현재 음료를 마시고 귀가하는 데 걸리는 시간을 뺀 값입니다.

바에 도착한 후 첫 맥주를 주문하고 술을 마시기 시작합니다.

$timeToGoHome = '23';  // Let's give ourselves an hour for last call and getting home

function orderAndDrinkBeer($timeToGoHome) {  // Let's create the function that's going to call itself.
    $beer = New Beer();  // Let's grab ourselves a new beer
    $currentTime = date('G'); // Current hour in 24-hour format

    while ($beer->status != 'empty') {  // Time to commence the drinking loop
        $beer->drink();  // Take a sip or two of the beer(or chug if that's your preference)
    }

    // Now we're out of the drinking loop and ready for a new beer

    if ($currentTime < $timeToGoHome) { // BUT only if we got the time
        orderAndDrinkBeer($timeToGoHome);  // So we make the function call itself again!
    } else {  // Aw, snap!  It is time :S
        break; // Let's go home :(
    }
}

이제 맥주를 충분히 마시지 못했기 때문에 아내가 집에 제시간에 와도 소파에서 자게 할 것 같아서--

하지만 재귀는 거의 그런 식이죠

자신을 호출하는 함수입니다.트리와 같이 반복되는 특정 데이터 구조를 걷는 데 유용합니다.HTML DOM이 대표적인 예입니다.

javascript의 트리 구조와 트리를 '걷기' 위한 재귀 함수의 예입니다.

    1
   / \
  2   3
     / \
    4   5

--

var tree = {
  id: 1,
  left: {
    id: 2,
    left: null,
    right: null
  },
  right: {
    id: 3,
    left: {
      id: 4,
      left: null,
      right: null
    },
    right: {
      id: 5,
      left: null,
      right: null
    }
  }
};

트리를 걷기 위해 동일한 함수를 반복 호출하여 현재 노드의 하위 노드를 동일한 함수로 전달합니다.그런 다음 왼쪽 노드에서 함수를 다시 호출하고 오른쪽에서 호출합니다.

이 예에서는 트리의 최대 깊이를 가져옵니다.

var depth = 0;

function walkTree(node, i) {

  //Increment our depth counter and check
  i++;
  if (i > depth) depth = i;

  //call this function again for each of the branch nodes (recursion!)
  if (node.left != null) walkTree(node.left, i);
  if (node.right != null) walkTree(node.right, i);

  //Decrement our depth counter before going back up the call stack
  i--;
}

마지막으로 함수를 호출합니다.

alert('Tree depth:' + walkTree(tree, 0));

재귀를 이해하는 좋은 방법은 실행 시 코드를 단계별로 살펴보는 것입니다.

간단히 말하면, 재귀 함수는 자신을 호출하는 함수입니다.

함수가 정의되지 않은 유한한 시간 동안 작업을 수행하도록 호출하는 것은 매우 간단합니다.내 코드의 예, 다단계 카테고리 트리를 채우는 함수

함수 카테고리_tree parent=0,$parent="){$q="parent_id="categorye에서 id,name을 선택하십시오."$parent;$rs=syslog_syslogq);반면, rd=syslog_syslog_objectsrs){echo " id." " > "$syslog" 입니다.$rd->name. " ) ;
category_tree"rd->id,$syslog.--';}}

재귀는 "이것을 끝날 때까지 다시 하라"는 화려한 표현이다.

다음 두 가지 중요한 점이 있습니다.

  1. 기본 사례 - 목표를 달성해야 합니다.
  2. 테스트 - 목적지에 도달했는지 확인하는 방법.

간단한 작업을 상상해 보십시오.책 더미를 알파벳 순으로 정렬하세요.간단한 과정은 처음 두 권의 책을 분류하는 것이다.다음은 재귀적인 부분입니다.책이 더 있나요?만약 그렇다면, 다시 하세요."do it again"은 재귀입니다."더 많은 책이 있나요?"가 시험입니다.그리고 "No, no more books"가 기본 케이스입니다.

재귀는 루프의 대체 수단입니다. 루프가 코드를 더 선명하게 하거나 우아하게 만드는 경우는 거의 없습니다.Progman의 답변에서 좋은 예를 들 수 있습니다.만약 그가 재귀를 사용하지 않는다면, 그는 그가 현재 어떤 디렉토리에 있는지 추적해야 합니다(이것을 상태라고 부릅니다). 재귀로 인해 그는 스택(메서드의 변수와 반환 주소가 저장되는 영역)을 사용하여 부기를 수행할 수 있습니다.

표준 예제 요인 및 피보나찌는 루프로 대체하기 쉽기 때문에 개념을 이해하는 데 유용하지 않습니다.

내가 여기 있다는 것을 알았을 때 찾은 최고의 설명: http://www.elated.com/articles/php-recursive-functions/

한 가지 이유:

호출된 인스턴스가 메모리에 생성될 때의 함수(새 인스턴스 생성)

따라서 재귀 함수는 자신을 호출하는 것이 아니라 다른 인스턴스를 호출하는 것입니다. 따라서 메모리 내의 하나의 함수가 어떤 마법을 수행하는 것이 아닙니다.메모리 내의 몇 가지 값을 반환하는 몇 가지 인스턴스는 예를 들어 함수 a가 함수 b를 호출할 때 이 동작은 동일합니다.인스턴스가 2개 있고, 그 자체의 새로운 인스턴스라고 불리는 재귀 함수도 있습니다.

종이에 인스턴스(instance)를 사용하여 메모리를 그려 보십시오. 그러면 의미가 있습니다.

디렉토리 트리를 통과하는 것이 좋은 예입니다.어레이를 처리하는 것과 유사한 작업을 수행할 수 있습니다.다음은 문자열, 단순 문자열 배열 또는 모든 깊이의 문자열 중첩 배열을 단순하게 처리하는 매우 간단한 재귀 함수입니다. 문자열 또는 배열 값에서 "hello" 인스턴스를 "goodbye"로 대체합니다.

function replaceHello($a) {
    if (! is_array($a)) {
        $a = str_replace('hello', 'goodbye', $a);
    } else {
        foreach($a as $key => $value) {
            $a[$key] = replaceHello($value);
        }
    }
    return $a
}

처리 중인 "처리 대상"이 배열이 아니기 때문에 종료 시기를 알 수 있습니다.예를 들어 replace를 호출한 경우안녕하세요. '안녕'을 반환합니다.문자열 배열을 전송하면 배열의 모든 멤버에 대해 한 번 호출되지만 처리된 배열이 반환됩니다.

Anthony Forloney의 예에 특정 값(예: "1")을 추가하면 모든 것이 명확해집니다.

function fact(1) {
  if (1 === 0) { // our base case
  return 1;
  }
  else {
  return 1 * fact(1-1); // <--calling itself.
  }
}

오리지널:

function fact($n) {
  if ($n === 0) { // our base case
    return 1;
  }
  else {
  return $n * fact($n-1); // <--calling itself.
  }
}

기본적으로는 이거죠.끝날 때까지 계속 자신을 부른다.

void print_folder(string root)
{
    Console.WriteLine(root);
    foreach(var folder in Directory.GetDirectories(root))
    {
        print_folder(folder);
    }
}

루프에도 대응!

void pretend_loop(int c)
{
    if(c==0) return;
    print "hi";
    pretend_loop(c-);
}

검색해 볼 수도 있어요.「의미하셨습니까」(클릭해 주세요)에 주의해 주세요.http://www.google.com/search?q=recursion&spell=1

다음은 재귀가 포함된 매우 간단한 요인 예제입니다.

인수분류는 매우 쉬운 수학 개념입니다.5! 라고 쓰여있고, 이것은 5 * 4 * 3 * 2 * 1 입니다. 그래서 6!은 720이고 4!는 24입니다.

function factorial($number) { 

    if ($number < 2) { 
        return 1; 
    } else { 
        return ($number * factorial($number-1)); 
    } 
}

이게 당신에게 도움이 되길 바랍니다.:)

단순한 예제의 재귀적(Y)이 기능합니다.

<?php 


function factorial($y,$x) { 

    if ($y < $x) { 
        echo $y; 
    } else { 
        echo $x; 
        factorial($y,$x+1);
    } 
}

$y=10;

$x=0;
factorial($y,$x);

 ?>

여기 실용적인 예가 있습니다(이미 몇 가지 좋은 예가 있습니다).나는 단지 거의 모든 개발자에게 유용한 것을 추가하고 싶었다.

개발자는 API 또는 객체 또는 어레이의 응답과 같이 객체를 해석해야 합니다.

이 함수는 처음에 매개 변수만 포함할 수 있는 개체를 구문 분석하기 위해 호출됩니다. 그러나 개체에 다른 개체나 배열도 포함되어 있으면 어떻게 됩니까?이는 대처해야 하며, 대부분의 경우 기본 함수는 이미 이 작업을 수행하므로 함수는 (키 또는 값이 개체 또는 배열임을 확인한 후) 자신을 다시 호출하고 이 새로운 개체 또는 배열에 대해 구문 분석합니다.최종적으로 반환되는 것은 가독성을 위해 각 파라미터를 한 줄에 직접 작성하는 문자열입니다만, 그 값을 로그 파일에 기록하거나 DB에 삽입하거나 할 수도 있습니다.

추가했습니다.$prefixparameter: 부모 요소를 사용하여 엔드 변수를 설명함으로써 값이 무엇에 관련되어 있는지 확인할 수 있습니다.null 값 등은 포함되지 않지만 이 예에서 수정할 수 있습니다.

오브젝트가 있는 경우:

$apiReturn = new stdClass();
$apiReturn->shippingInfo = new stdClass();
$apiReturn->shippingInfo->fName = "Bill";
$apiReturn->shippingInfo->lName = "Test";
$apiReturn->shippingInfo->address1 = "22 S. Deleware St.";
$apiReturn->shippingInfo->city = "Chandler";
$apiReturn->shippingInfo->state = "AZ";
$apiReturn->shippingInfo->zip = 85225;
$apiReturn->phone = "602-312-4455";
$apiReturn->transactionDetails = array(
    "totalAmt" => "100.00",
     "currency" => "USD",
     "tax" => "5.00",
     "shipping" => "5.00"
);
$apiReturn->item = new stdClass();
$apiReturn->item->name = "T-shirt";
$apiReturn->item->color = "blue";
$apiReturn->item->itemQty = 1;

및 용도:

var_dump($apiReturn);

다음과 같이 반환됩니다.

개체(d 클래스)#1 () > > = > > > > > > > = > []]] [y (4) {]=>> 스트랩) gt> 스트링g(6) "100.00" ["tem"]=> string(3) "USD" ["tax"]=> string(4) "5.00" ["tem"]=> string(4) "5.00" } ["item"=> object(stdClass) #3(3) {" =" (7-color)"

각 파라미터의 줄 바꿈이 있는 문자열로 해석하는 코드를 다음에 나타냅니다.

function parseObj($obj, $prefix = ''){
    $stringRtrn = '';
    foreach($obj as $key=>$value){
        if($prefix){
            switch ($key) {
                case is_array($key):
                    foreach($key as $k=>$v){
                        $stringRtrn .= parseObj($key, $obj);
                    }
                    break;
                case is_object($key):
                    $stringRtrn .= parseObj($key, $obj);
                    break;
                default:
                    switch ($value) {
                        case is_array($value):
                            $stringRtrn .= parseObj($value, $key);
                            break;
                        case is_object($value):
                            $stringRtrn .= parseObj($value, $key);
                            break;
                        default:
                            $stringRtrn .= $prefix ."_". $key ." = ". $value ."<br>";
                            break;
                    }
                    break;
            }
        } else { // end if($prefix)
            switch($key){
                case is_array($key):
                    $stringRtrn .= parseObj($key, $obj);
                    break;
                case is_object($key):

                    $stringRtrn .= parseObj($key, $obj);
                    break;
                default:
                    switch ($value) {
                        case is_array($value):
                            $stringRtrn .= parseObj($value, $key);
                            break;
                        case is_object($value):
                            $stringRtrn .= parseObj($value, $key);
                            break;                      
                        default:
                            $stringRtrn .= $key ." = ". $value ."<br>";
                            break;
                    } // end inner switch 
            } // end outer switch
        } // end else
    } // end foreach($obj as $key=>$value)
    return $stringRtrn;
} // END parseObj()

그러면 다음과 같이 개체가 반환됩니다.

shippingInfo_fName = Bill
shippingInfo_lName = Test
shippingInfo_address1 = 22 S. Deleware St.
shippingInfo_city = Chandler
shippingInfo_state = AZ
shippingInfo_zip = 85225
phone = 602-312-4455
transactionDetails_totalAmt = 100.00
transactionDetails_currency = USD
transactionDetails_tax = 5.00
transactionDetails_shipping = 5.00
item_name = T-shirt
item_color = blue
item_itemQty = 1

nested switch 스테이트먼트를 실행해, 와의 혼동을 회피했습니다.if . . . ifelse . . . else 같은 만약 도움이 된다면, 그냥 if conditionals를 요청하시면 제가 필요한 사람들을 위해 붙일 수 있습니다.

카프레카 상수에 사용되는 재귀

function KaprekarsConstant($num, $count = 1) {
    $input = str_split($num);
    sort($input);

    $ascendingInput  = implode($input);
    $descendingInput = implode(array_reverse($input));

    $result = $ascendingInput > $descendingInput 
        ? $ascendingInput - $descendingInput 
        : $descendingInput - $ascendingInput;

    if ($result != 6174) {
        return KaprekarsConstant(sprintf('%04d', $result), $count + 1);
    }

    return $count;

}

함수는 Kaprekars에 일정하게 도달할 때까지 계산 결과를 사용하여 계속 호출하며, 이 때 계산한 횟수를 반환합니다.

/edit Kaprekars Constant를 모르는 사람은 적어도 두 개의 다른 숫자를 가진 4자리 숫자를 입력해야 합니다.

재귀는 어떤 것이 자신과 유사한 버전을 포함하거나 사용할 때 발생합니다.컴퓨터 프로그래밍에 대해 구체적으로 말할 때 함수가 자신을 호출할 때 재귀가 발생합니다.

다음 링크는 재귀에 대해 더 잘 이해하는 데 도움이 됩니다. 지금까지 배운 내용 중 이것이 가장 좋다고 생각됩니다.

실행 중 내부(재귀) 함수가 호출되는 방법을 이해하기 위한 예제가 포함되어 있습니다.

기사를 검토해 주시고, 만약 기사가 망가질 경우를 대비해서 테스트 프로그램을 붙여 두겠습니다.로컬 서버에서 프로그램을 실행하여 실제 동작을 확인할 수 있습니다.

https://www.elated.com/php-recursive-functions/

<?php

function factorial( $n ) {

  // Base case
  if ( $n == 0 ) {
    echo "Base case: $n = 0. Returning 1...<br>";
    return 1;
  }

  // Recursion
  echo "$n = $n: Computing $n * factorial( " . ($n-1) . " )...<br>";
  $result = ( $n * factorial( $n-1 ) );
  echo "Result of $n * factorial( " . ($n-1) . " ) = $result. Returning $result...<br>";
  return $result;
}

echo "The factorial of 5 is: " . factorial( 5 );

?>

언급URL : https://stackoverflow.com/questions/2648968/what-in-laymans-terms-is-a-recursive-function-using-php

반응형