Есть ли примеры взаимной рекурсии?
существуют ли примеры рекурсивной функции, которая вызывает другую функцию, которая также вызывает первую ?
пример :
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