разъяснение концепции рекурсии

0

У меня есть сомнения в рекурсии, если я напишу код, как показано ниже

inorder(p){
if(p!=NULL){
 inorder(p->link);  //step 1
 cout<<p->info<<" "; //step 2
 inorder(p->link);  //step 3
}
} 

Здесь я сомневаюсь, что, когда выполняется шаг 1, управление возвращается к функции, а затем снова выполняется шаг 1, и снова элемент управления возвращается к функции до p, является NULL, если это процесс, то как управление будет переходите к шагу 2, который является "cout" и к шагу 3...

Я не могу закодировать код в своем мозгу...

  • 0
    Две ссылки разные, верно? Скажи, left и right ? ..
  • 0
    Идея состоит в том, что, поскольку вы делаете несколько вызовов функций, он не останавливается, когда возвращается один / несколько из них. Вы хотите, чтобы они достигли своего конца, чтобы каждый отдельный звонок мог продолжаться вниз. Думайте об этом так: когда вызов возвращается, тот, который сделал этот вызов функции, будет завершен с этой строкой кода и продолжится. Это помогает напечатать некоторые вещи и рисовать, используя ручку и бумагу.
Показать ещё 1 комментарий
Теги:
recursion

8 ответов

1

Прежде чем "управление возвращается к одной и той же функции" на шаге 1, CPU делает важный шаг: он отмечает место в коде inorder где ему нужно перезапустить выполнение, как только "второй уровень" inorder вернется (это пятно сразу после шаг 1). Там "второй уровень" снова отмечает позицию возврата, прежде чем перейти на "третий уровень", "четвертый уровень" и т.д. В конце концов, уровень N -th получает NULL, поэтому он сразу возвращается. Затем уровень N-1 -th получит распечатку info и inorder во второй раз. Теперь место возврата отличается - оно сразу после шага 3. Как только уровень N -th заканчивается, уровень N-1 -st также заканчивается, возвращаясь к уровню N-2 -nd, затем до N-3 -rd ] и т.д., пока не выйдет самый первый уровень.

Вот пример дерева:

      A
    /   \
   B     C
       /   \
      D     E

Процесс обхода порядка выглядит следующим образом:

inorder(A)            -- step 1, level 1
  inorder(B)          -- step 1, level 2
    inorder(NULL)     -- returns
    cout << B         -- step 2, level 2
    inorder(NULL)     -- returns
  return              -- level 2 returns 
  cout << A           -- step 2, level 1
  inorder(C)          -- step 3, level 2
    inorder(D)        -- step 1, level 3
      inorder(NULL)   -- returns
      cout << D       -- step 2, level 3
      inorder(NULL)   -- returns
    return            -- level 3 returns
    cout << C         -- step 2, level 2
    inorder(E)        -- step 1, level 3
      inorder(NULL)   -- returns
      cout << E       -- step 2, level 3
      inorder(NULL)   -- returns
    return            -- level 3 returns
  return              -- level 2 returns
return                -- level 1 returns
0

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

Другими словами, когда вы вызываете inorder из строки, указанной как шаг 1, а переданный параметр p равен NULL, когда функция выходит, вызывающая функция запускает выполнение в строке, указанной как шаг 2.

Дополнительную информацию см. на странице wikipedia http://en.wikipedia.org/wiki/Call_stack.

Понимание концепций, связанных со стеками вызовов, поможет понять, что происходит с рекурсией.

0

Когда выполняется первый вызов inorder (p-> link), рассмотрите его как контрольную точку. Он будет продолжать звонить до точки, в которой он достигнет NULL. Затем выполняется строка 2, а для второго вызова inorder (p-> link) выполняется то же самое. Таким образом, это образует дерево


          inorder(p->link) -> coutinfo ->   inorder(p->link) 
             /   ^                                  /   ^     
            V   /                                  V   /      
         inorder()->cout->inorder()              inorder()->cout->inorder()
           .  ^              /  \                  .  ^                /  \
           .  |              .  .                  .  |                .  .
           .  |                                    .  |
   inorder(p->link) //(p->link is NULL)      inorder(p->link) //(p->link is NULL)


0

Рассмотрите игру, было ли у вас 5 сообщений в разных местах вашего дома. Каждое сообщение приводит вас к следующему. Чтобы выиграть игру, вы должны найти все 5 сообщений и вернуть их игровому хосту. Тем не менее, вы не можете получить сообщения, когда найдете их... вы должны помнить свое местоположение и забрать их в противоположном порядке, который вы их нашли.

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

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

Поиск первой подсказки похож на ваш первый вызов "inorder()". Следуя подсказке ко второму подсказку, ваш вызов "inorder (p-> link)". Выбор подсказки после всех подсказок был найден, как когда вы возвращаетесь к "step2" в своем коде.

0

Предположим, что p указывает на A, p->link (то есть A.link) называется q и указывает на B, а q->link (то есть B.link) равна NULL, назовите ее r.

  p      q      r
----->A----->B----->0

Теперь мы вызываем inorder(p).

  1. p не является NULL, поэтому inorder (p) вызывает inorder (q) (шаг 1)
  2. q не является NULL, поэтому inorder (q) вызывает inorder (r) (шаг 1)
  3. r равно NULL, поэтому inorder (r) пропускает блок и возвращает управление inorder (q)
  4. inorder (q) печатает B.info (шаг 2)
  5. inorder (q) вызывает inorder (r) (шаг 3), который снова возвращает управление inorder (q), которое возвращает управление inorder (p)
  6. inorder (p) печатает A.info (шаг 2)
  7. inorder (p) вызывает inorder (q) (шаг 3), который снова запускается через 2-5 (снова печать B.info), затем inorder (p) возвращает управление тому, что называется.
0

Я предполагаю, что ваш код правильный. Вы пытаетесь распечатать связанный список ниже:

inorder(p){ 
 if(p!=NULL)
 {
   inorder(p->link);   //step 1 to navigate to next link
   cout<<p->info<<" "; //step 2 as main operation
   inorder(p->link);   //step 3 to navigate to next link
 }
} 

Перевести на английский

inorder(p)
{
  if p points to a linked list
  {
    print the list p points to;
    print content of p;
    print the list p points to again;
  }

  if p points to a null linked list     
  {
     do nothing;
  }
}

Тогда связанный список 1 → 2 → 3 выведет ((3) 2 (3)) 1 ((3) 2 (3))

Как вы можете видеть, элемент управления переходит только к шагу 2, как только шаг 1 встречает нулевой список. После того, как информация распечатана, она затем переходит к шагу 3.

Следовательно,

  • Когда связанный список в узле "3",

    шаг 1 встречает null и return;

    шаг 2 распечатывает 3;

    шаг 3 встречает null и return;

  • Когда связанный список в узле "2"

    шаг 1 выполняет все, что он делает на узле "3"; //печать 3

    шаг 2 распечатывает 2;

    шаг 3 выполняет все, что он делает на узле "3"; //печать 3

  • когда связанный список в узле "1"

    шаг 1 выполняет все, что он делает на узле "2"; //печать 3 2 3

    шаг 2 распечатывает 1;

    этап 3 выполняет все, что он делает на узле "2"; // печать 3 2 3

0

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

Рассмотрим этот простой код в C++, который хорошо демонстрирует рекурсию.

int fact(int x)
{
    if(x==1)
        return 1;
    x = x*fact(x-1);
    return x;
}

Это вводит целое число, а затем вызывает себя после декрементации целого числа, пока целое число равно 1 и не вернет x. Обратите внимание, что строка 'return x;' не вызывается, пока линия не закончится.

0

вы должны узнать о call stack если хотите понять, как работает рекурсия. Вот ссылка. Надеюсь, это поможет...

Ещё вопросы

Сообщество Overcoder
Наверх
Меню