Модераторы: bsa

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Рекурсия разложенная "по полочкам" 
:(
    Опции темы
n199a
  Дата 30.5.2013, 19:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 129
Регистрация: 17.11.2011

Репутация: нет
Всего: нет



У меня мозг кипит от того, как же понять, что из себя представляет рекурсия, smile но я хочу разобраться. 
Определение рекурсии я знаю  smile .
Расскажите, пожалуйста, по-подробнее про это.

Вот код для вычисления факториала с помощью рекурсии (странно, что, все авторы приводят первых примером вычисление факториала):
Код

int Fact(int N)
{
  if (N < 1) return 0;
  else if (N == 1) return 1;
  else return N * Fact(N-1);
}


Давай я распишу все подробно, т.к. это "разложение по полочкам" будет только полезным для понимания.
Пусть N будет равно трем.
1: int Fact(int N)
Объявляем функцию Fact с типом int. В скобках объявляем переменную N типа int, значение которой будет возвращать данная функция Fact.
2: Без комментариев
3: Если введенное значение N будет меньше единицы, то выход по коду ошибки 0 в функцию. Другими словами завершаем вычисления.
4: Тогда если введенное значение N будет равно единице, то выход по коду ошибки 1. Возвращаем (return) единицу.
5: Если не то и не другое (описанное выше), то возвращаем в функцию Fact число, равное 3* (а вот что и как тут происходит меня заводит в тупик, объясните пожалуйста).
PM MAIL   Вверх
mexanika
Дата 30.5.2013, 19:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 6
Регистрация: 9.1.2011

Репутация: нет
Всего: нет



дальше вызывается Fact(2)

Добавлено через 2 минуты и 47 секунд
в результате: 3 * 2 * 1 = 6
PM MAIL   Вверх
Alexeis
Дата 30.5.2013, 20:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 4
Всего: 459



return возвращает не код ошибки, а вычисленный факториал. Когда функция вызывает сама себя, то происходит так как если бы вызвали не себя, а любую другую функцию. Т.е. переходим на 1ю строчку и начинаем все вычислять с новым входным параметром. При этом предыдущий вызов еще не завершился, он ожидает когда Fact(N-1); вернет свое значение чтобы продолжить свое выполнение. Фактически получаем число вложенных вызовов равное N . В каждом новом вызове N уменьшается на единицу, пока не станет равным 1, в этом случае сработает условие 4й строки и функция перестанет сама себя вызывать. После того как завершилась функция с N==1 это значение попадет в вызов где N==2 и 1 умножиться на 2 . Произведение 1 * 2 и есть результат функции Fact(2) . Fact(2) вернет значение 2 в вызов Fact(3) в котором оно умножиться на текущий N, который уже равен 3м, что даст 2*3=6 и так далее, пока мы не вернемся в самый первый вызов, который Fact(N) . В конечном итоге там уже получиться N*N-1*N-2...1


Этот ответ добавлен с нового Винграда - http://vingrad.com
PM ICQ Skype   Вверх
feodorv
Дата 30.5.2013, 22:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(n199a @  30.5.2013,  20:05 Найти цитируемый пост)
В скобках объявляем переменную N типа int, значение которой будет возвращать данная функция Fact.

Я не придираюсь, я хочу понять. 
Вы действительно утверждаете, что функция Fact будет возвращать значение переменной N, которая объявлена в скобках?


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
n199a
Дата 30.5.2013, 22:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 129
Регистрация: 17.11.2011

Репутация: нет
Всего: нет



else return N * Fact(N-1);
Или можно так объяснить?  smile 
Возьмем N=5.
5 * a-1 * b-1 * c-1 * d-1     // это целые числа, которые будут получаться на каждом последующем шаге, пока не достигнем N == 1
a      b       c        d       e      // обозначения каждого шага
Т.е. обозначим каждый шаг по букве (a,b,c,d,e) и ниже записаны просто результаты.
a=5;
b=5-1=4
c=4-1=3
d=3-1=2
e=2-1=1
В итоге в Fact получится a*b*c*d*e=5*4*3*2*1=120



Это сообщение отредактировал(а) n199a - 30.5.2013, 23:06
PM MAIL   Вверх
n199a
Дата 30.5.2013, 23:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 129
Регистрация: 17.11.2011

Репутация: нет
Всего: нет



Цитата(mexanika @  30.5.2013,  19:17 Найти цитируемый пост)
дальше вызывается Fact(2)

Вот меня это и вводит в заблуждение. Т.е. Fact(2) = 2 ?
Код

else return N * Fact(N-1);
Пусть N = 3, тогда код будет выглядеть так: (?)
else return 3 * Fact(3-1);  равносильно else return 3 * 2; 


Добавлено через 5 минут и 42 секунды
Цитата(feodorv @  30.5.2013,  22:06 Найти цитируемый пост)
Я не придираюсь, я хочу понять. 
Вы действительно утверждаете, что функция Fact будет возвращать значение переменной N, которая объявлена в скобках? 

А как тогда правильно? smile 
PM MAIL   Вверх
Arantir
Дата 30.5.2013, 23:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Рыбак без удочки
**


Профиль
Группа: Участник
Сообщений: 960
Регистрация: 18.11.2012

Репутация: нет
Всего: 55



Это ближе к истине...

Функция — не одноразовый код. Ее можно вызывать сколько угодно, но под каждый вызов выделяется собственная область. Ее переменные в этих вызовах не пересекаются друг с другом. Она просто выполняет свой код, используя заданные аргументы, и возвращает значение.
Вызов функции изнутри самой себя абсолютно ничем не отличается от ее вызова извне. 


Цитата(n199a @  30.5.2013,  18:05 Найти цитируемый пост)
5: Если не то и не другое (описанное выше), то возвращаем в функцию Fact число, равное 3*

Читайте вызов функции в коде так же, как функции на уроке алгебры в школе.
Если пишем "x = 5 * cos(n)", то нету никакого никакого "возвращаем в косинус...". Имеется ввиду, что 5 умножается на значение косинуса от аргумента n.
Код

return N * Fact(N-1);

N умножается на значение, которое вернула функция Fact при значении аргумента равном N-1. И это точно такое же значение, как если бы вы эту функцию вызвали где-то еще, а не изнутри себя.

Вот так по цепочке постоянно вызывая эту функцию компьютер приходит к Fact(1) из которой он просто возвращает единицу. Дальше вверх по цепочке во всех местах, где компьютер ждет, пока выполнится эта функция.
Цитата

В итоге в Fact получится a*b*c*d*e=5*4*3*2*1=120

Да, все именно так.

Добавлено @ 23:26
Чтобы проще представить, запишите это в алгебраическом представлении...
Внутренние функции — это просто как вложенные скобочки. Вы ведь нормально воспринимаете запись "cos(cos(sin(5)))". вот тут то же самое.

Код

Fact(N) = N * Fact(N-1)
Fact(5) = 5 * (5-1 * (5-1-1 * (5-1-1-1 * (5-1-1-1-1 * 1)))) = 5 * (4 * (3 * (2 * (1 * 1)))) = 5 * 4 * 3 * 2 * 1


Это сообщение отредактировал(а) Arantir - 30.5.2013, 23:29


--------------------
interface Жопа {
    // ATTENTION: has to be implemented by every class of the project for proper project work
}
PM   Вверх
mes
Дата 30.5.2013, 23:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 79
Всего: 250



Может так поможет ?

Код

#include <iostream>
 
int Fact(int N)
{
  if (N < 1)
  { 
    return 0;  
  }
  else if (N == 1)
  {
    std::cout << 1 <<"=";
    return 1;
  }
  else
  {
    std::cout << N <<"*";
    return N * Fact(N-1);
  }
}
 
int main()
{
  for (int i=0; i<10; ++i)
  {
    std::cout << "Fact("<< i <<")=";
    std::cout << Fact(i);
    std::cout << std::endl;    
  }
}


Добавлено через 1 минуту и 16 секунд
Цитата

Fact(0)=0
Fact(1)=1=1
Fact(2)=2*1=2
Fact(3)=3*2*1=6
Fact(4)=4*3*2*1=24
Fact(5)=5*4*3*2*1=120
Fact(6)=6*5*4*3*2*1=720
Fact(7)=7*6*5*4*3*2*1=5040
Fact(8)=8*7*6*5*4*3*2*1=40320
Fact(9)=9*8*7*6*5*4*3*2*1=362880



--------------------
PM MAIL WWW   Вверх
volatile
Дата 30.5.2013, 23:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(n199a @  30.5.2013,  19:05 Найти цитируемый пост)
 if (N < 1) return 0;

Неправильно, факториал 0 рвен 1
PM MAIL   Вверх
mes
Дата 30.5.2013, 23:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 79
Всего: 250



Цитата(volatile @  30.5.2013,  22:35 Найти цитируемый пост)
Неправильно, факториал 0 рвен 1 

 smile 
не столь важно, вопрос о рекурсии кал таковой smile


--------------------
PM MAIL WWW   Вверх
volatile
Дата 30.5.2013, 23:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(mes @  30.5.2013,  23:36 Найти цитируемый пост)
не столь важно

да я не настаиваю ... 
 smile 
PM MAIL   Вверх
Arantir
Дата 31.5.2013, 00:00 (ссылка) |  (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Рыбак без удочки
**


Профиль
Группа: Участник
Сообщений: 960
Регистрация: 18.11.2012

Репутация: нет
Всего: 55



Цитата(mes @  30.5.2013,  22:36 Найти цитируемый пост)
вопрос о рекурсии кал

Забавная цитатка вышла  smile 



--------------------
interface Жопа {
    // ATTENTION: has to be implemented by every class of the project for proper project work
}
PM   Вверх
EgoBrain
Дата 31.5.2013, 03:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 537
Регистрация: 23.3.2008
Где: Комната

Репутация: нет
Всего: 2



Цитата(mes @  30.5.2013,  23:36 Найти цитируемый пост)
не столь важно, вопрос о рекурсии кал таковой smile 


mes подытожил: "рекурсия - кал"... в топку рекурсию..  smile

Добавлено через 3 минуты и 5 секунд
Код

#include <iostream>

using namespace std;

int main()
{
       cout<<"Программа отработала"<<endl;
       getchar();
       return main();
}

Удобно рекурсировать главную функцию, когда нужно проверить работу программы при разных условиях/обрабатываемых данных/входных параметрах.
PM MAIL ICQ Skype   Вверх
borisbn
Дата 31.5.2013, 06:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 21
Всего: 135



EgoBrain, вызов main запрещён по стандарту. Такое работает только в студии. В GCC - нет.


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
mes
Дата 31.5.2013, 10:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 79
Всего: 250



Цитата(EgoBrain @  31.5.2013,  02:13 Найти цитируемый пост)
mes подытожил: "рекурсия - кал"... в топку рекурсию.. 

хоть и в топку, понять ее все равно не мешало бы smile

вот еще один примерчик, для эксперимента :
Код

#include <cstdio>

struct Scope
{
  int mIndex;
  Scope(int idx) : mIndex(idx) 
  {
    for (int i=0; i<mIndex; ++i)
      printf(".");

    printf("-> %d\n",mIndex );  
  }
 ~Scope() 
 {
    for (int i=0; i<mIndex; ++i)
      printf(".");

    printf("<- %d\n",mIndex ); 
 }   
};

void f(int i, int j)
{
  Scope scope(i);

  if (i>=j) return; // exit

  f(i+1, j-1);

//~Scope(i);
}

int main()
{
  f(5,10);
}



--------------------
PM MAIL WWW   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.1130 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.