Есть ли примеры взаимной рекурсии?

существуют ли примеры рекурсивной функции, которая вызывает другую функцию, которая также вызывает первую ?

пример :

function1()
{    
    //do something 
    f2();
    //do something
}

function2()
{
    //do something 
    f1();
    //do something
}

7 ответов


взаимная рекурсия распространена в коде, который анализирует математические выражения (и другие грамматики). Рекурсивный парсер спуска, основанный на приведенной ниже грамматике, естественно будет содержать взаимную рекурсию:expression-terms-term-factor-primary-expression.

expression
    + terms
    - terms
    terms

terms
    term + terms
    term - terms

term
    factor
    factor * term
    factor / term

factor
    primary
    primary ^ factor

primary
    ( expression )
    number
    name
    name ( expression )

правильным термином для этого является взаимная рекурсия.

http://en.wikipedia.org/wiki/Mutual_recursion

на этой странице есть пример, я воспроизведу здесь на Java:

boolean even( int number )
{    
    if( number == 0 )
        return true;
    else
        return odd(abs(number)-1)
}

boolean odd( int number )
{
    if( number == 0 )
        return false;
    else
        return even(abs(number)-1);
}

где abs (n ) означает возврат абсолютного значения числа.

очевидно, что это не эффективно, просто, чтобы продемонстрировать точку.


примером может быть алгоритм minmax, обычно используемый в игровых программах, таких как шахматы. Начиная с верхней части игрового дерева, цель состоит в том, чтобы найти максимум стоимость всех узлов на уровне ниже, значения которых определяются как минимум значений узлов ниже, значения которых определяются как максимум из значений ниже, чьи значения ...


это немного надуманно и не очень эффективно, но вы можете сделать это с помощью функции для вычисления чисел Фибоначчи, как в:


fib2(n) { return fib(n-2); }

fib1(n) { return fib(n-1); }

fib(n)
{
  if (n>1)
    return fib1(n) + fib2(n);
  else
    return 1;
}

в этом случае его эффективность может быть значительно повышена, если язык поддерживает memoization


в языке с правильными хвостовыми вызовами взаимная хвостовая рекурсия - очень естественный способ реализации автоматов.


Я могу думать о двух общих источниках взаимной рекурсии.

функции, имеющие дело с взаимно рекурсивными типами

рассмотрим абстрактное дерево синтаксиса (AST), которое хранит информацию о местоположении в каждом узле. Тип может выглядеть следующим образом:

type Expr =
  | Int of int
  | Var of string
  | Add of ExprAux * ExprAux
and ExprAux = Expr of int * Expr

самый простой способ написать функции, которые управляют значениями этих типов, - это написать взаимно рекурсивные функции. Например, функция для поиска набора свободных переменных:

let rec freeVariables = function
  | Int n -> Set.empty
  | Var x -> Set.singleton x
  | Add(f, g) -> Set.union (freeVariablesAux f) (freeVariablesAux g)
and freeVariablesAux (Expr(loc, e)) =
  freeVariables e

государство машины

рассмотрим государственную машину, которая включена, выключена или приостановлена с инструкциями для запуска, остановки, паузы и возобновления (код f#):

type Instruction = Start | Stop | Pause | Resume

машина состояний может быть записана как взаимно рекурсивные функции с одной функцией для каждого состояния:

type State = State of (Instruction -> State)

let rec isOff = function
  | Start -> State isOn
  | _ -> State isOff
and isOn = function
  | Stop -> State isOff
  | Pause -> State isPaused
  | _ -> State isOn
and isPaused = function
  | Stop -> State isOff
  | Resume -> State isOn
  | _ -> State isPaused

вот мое закодированное решение. Для калькулятора приложение, которое выполняет *,/,- операции с использованием взаимной рекурсии. Он также проверяет наличие скобок (()), чтобы решить порядок приоритета.

Flow:: expression -> term -> factor -> expression 

    Calculator.h
    #ifndef CALCULATOR_H_
    #define CALCULATOR_H_

    #include <string>
    using namespace std;

    /****** A Calculator Class holding expression, term, factor ********/
    class Calculator
    {
    public:
        /**Default Constructor*/
        Calculator();

        /** Parameterized Constructor common for all exception
         * @aparam e exception value
         * */
        Calculator(char e);

        /**
         * Function to start computation
         * @param input - input expression*/
        void start(string input);

        /**
         * Evaluates Term*
         * @param input string for term*/
        double term(string& input);

         /* Evaluates factor*
         * @param input string for factor*/
        double factor(string& input);

         /* Evaluates Expression*
          * @param input string for expression*/
        double expression(string& input);


         /* Evaluates number*
          * @param input string for number*/
        string number(string n);

        /**
         * Prints calculates value of the expression
         * */
        void print();

        /**
         * Converts char to double
         * @param c input char
         * */
        double charTONum(const char* c);

        /**
         * Get error
         */
        char get_value() const;
        /** Reset all values*/
        void reset();
    private:
        int lock;//set lock to check extra parenthesis
        double result;// result
        char error_msg;// error message
    };

    /**Error for unexpected string operation*/
    class Unexpected_error:public Calculator
    {
    public:
        Unexpected_error(char e):Calculator(e){};
    };

    /**Error for missing parenthesis*/
    class Missing_parenthesis:public Calculator
    {
    public:
        Missing_parenthesis(char e):Calculator(e){};
    };

    /**Error if divide by zeros*/
    class DivideByZero:public Calculator{
    public:
        DivideByZero():Calculator(){};
    };
    #endif
    ===============================================================================

    Calculator.cpp

    //============================================================================
    // Name        : Calculator.cpp
    // Author      : Anurag
    // Version     :
    // Copyright   : Your copyright notice
    // Description : Calculator using mutual recursion in C++, Ansi-style
    //============================================================================

    #include "Calculator.h"
    #include <iostream>
    #include <string>
    #include <math.h>
    #include <exception>
    using namespace std;


    Calculator::Calculator():lock(0),result(0),error_msg(' '){

    }

    Calculator::Calculator(char e):result(0), error_msg(e) {

    }

    char Calculator::get_value() const {
        return this->error_msg;
    }

    void Calculator::start(string input) {
        try{
        result = expression(input);
        print();
        }catch (Unexpected_error e) {
            cout<<result<<endl;
            cout<<"***** Unexpected "<<e.get_value()<<endl;
        }catch (Missing_parenthesis e) {
            cout<<"***** Missing "<<e.get_value()<<endl;
        }catch (DivideByZero e) {
            cout<<"***** Division By Zero" << endl;
        }
    }

    double Calculator::expression(string& input) {
        double expression=0;
        if(input.size()==0)
            return 0;
        expression = term(input);
        if(input[0] == ' ')
            input = input.substr(1);
        if(input[0] == '+') {
            input = input.substr(1);
            expression += term(input);
        }
        else if(input[0] == '-') {
            input = input.substr(1);
            expression -= term(input);
        }
        if(input[0] == '%'){
            result = expression;
            throw Unexpected_error(input[0]);
        }
        if(input[0]==')' && lock<=0 )
            throw Missing_parenthesis(')');
        return expression;
    }

    double Calculator::term(string& input) {
        if(input.size()==0)
            return 1;
        double term=1;
        term = factor(input);
        if(input[0] == ' ')
            input = input.substr(1);
        if(input[0] == '*') {
            input = input.substr(1);
            term = term * factor(input);
        }
        else if(input[0] == '/') {
            input = input.substr(1);
            double den = factor(input);
            if(den==0) {
                throw DivideByZero();
            }
            term = term / den;
        }
        return term;
    }

    double Calculator::factor(string& input) {
        double factor=0;
        if(input[0] == ' ') {
            input = input.substr(1);
        }
        if(input[0] == '(') {
            lock++;
            input = input.substr(1);
            factor = expression(input);
            if(input[0]==')') {
                lock--;
                input = input.substr(1);
                return factor;
            }else{
                throw Missing_parenthesis(')');
            }
        }
        else if (input[0]>='0' && input[0]<='9'){
            string nums = input.substr(0,1) + number(input.substr(1));
            input = input.substr(nums.size());
            return stod(nums);
        }
        else {
            result = factor;
            throw Unexpected_error(input[0]);
        }
        return factor;
    }

    string Calculator::number(string input) {
        if(input.substr(0,2)=="E+" || input.substr(0,2)=="E-" || input.substr(0,2)=="e-" || input.substr(0,2)=="e-")
            return input.substr(0,2) + number(input.substr(2));
        else if((input[0]>='0' && input[0]<='9') || (input[0]=='.'))
            return input.substr(0,1) + number(input.substr(1));
        else
            return "";
    }

    void Calculator::print() {
        cout << result << endl;
    }

    void Calculator::reset(){
        this->lock=0;
        this->result=0;
    }
    int main() {

        Calculator* cal = new Calculator;
        string input;
        cout<<"Expression? ";
        getline(cin,input);
        while(input!="."){
            cal->start(input.substr(0,input.size()-2));
            cout<<"Expression? ";
            cal->reset();
            getline(cin,input);
        }
        cout << "Done!" << endl;
        return 0;
    }
    ==============================================================
    Sample input-> Expression? (42+8)*10 =
    Output-> 500