Форум программистов, компьютерный форум CyberForum.ru

Разобраться с рекурсивной функцией обхода бинарного дерева - C++

Восстановить пароль Регистрация
 
Faltfromoss
0 / 0 / 0
Регистрация: 28.03.2014
Сообщений: 31
11.07.2014, 21:21     Разобраться с рекурсивной функцией обхода бинарного дерева #1
Люди, помогите разобраться с рекурсивной функцией обхода бинарного дерева. Бьюсь головой об стену, не могу понять как она работает.

вот метод класса Tree для обхода дерева:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void Tree::Print(Subscriber * Node)
{
   if(Node != 0)
   {
      Print(Node->left);
            cout  << Node->FIO;
    (strlen (Node->FIO)<24)?cout<<"\t\t": cout<<"\t";
            cout<< Node->YearOfBirth<<"\t"
                << Node->Town<<"\t"
                << Node->Number<<"\t"
                << endl << endl;
      Print(Node->right);
   }
}
Из всего пройденного мною материала на данный момент - рекурсия - пока самое темное для меня место в ООП. Вышеприведенная функция написана не мной, я так полагаю она является неким шаблоном, в который я добавил свои значения которые нужно выводить, но я не могу вникнуть как она работает в принципе.
Мне нужно к простому выводу данных всего дерева добавить нумерацию списка, но как это сделать в рекурсивной функции не могу понять. Собственно непонимание работы самой рекурсии и приводит к тому, что не знаю как сделать нумерацию.
Если в цикле там все понятно:
C++
1
2
for (int i = 1; i<n; i++)
    cout<<i<<"...."<<endl;
то в рекурсии так не канает.
Решил поэкспериментировать, добавил в класс Tree счетчик Counter, который считает кол-во созданных объектов и попытался его использовать в таком контексте:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void Tree::Print(Subscriber * Node)
{
   if(Node != 0)
   {
      Counter--;
      Print(Node->left);
            cout  <<"   "<<++Counter<<". "<<Node->FIO;
    (strlen (Node->FIO)<24)?cout<<"\t\t": cout<<"\t";
            cout<< Node->YearOfBirth<<"\t"
                << Node->Town<<"\t"
                << Node->Number<<"\t"
                << endl << endl;
      Print(Node->right);
   }
}
Руководствовался домыслами, что пока Print () будет себя вызывать внутри (до момента Node == 0), то счетчик с n-го кол-ва объектов обнулится, а потом при возврате значений из стека в обратном порядке будет увеличиваться на единицу и будет, то, чего я добиваюсь, но при создании не скольких объектов и выводе их на экран все абоненты нумеруются одним и тем же номером:
"2. айлалэ....
2. айнана...."
В общем непонимание того, что ты пишешь или с чем работаешь - это печально
Вот, собственно просьба, просветите неуча как реализовать нумерацию и как вообще понять рекурсию :/
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
11.07.2014, 21:21     Разобраться с рекурсивной функцией обхода бинарного дерева
Посмотрите здесь:

C++ Рекурсия,заполнение массива рекурсивной функцией.
C++ Как запрограммировать в рекурсивной форме алгоритм бинарного поиска
Нужно количество цифр с рекурсивной функцией C++
программа с рекурсивной функцией C++
Написать программу с рекурсивной функцией C++
Написать программу с рекурсивной функцией вычисляющий выражение C++
C++ Создать структуру с рекурсивной функцией
Процедура обхода для дерева C++
Процедура обхода для дерева C++
Разница между рекурсивной функцией и обычной C++
Программа с рекурсивной функцией C++
C++ Вывод обхода дерева в файл

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
olper
24 / 24 / 11
Регистрация: 02.12.2013
Сообщений: 75
11.07.2014, 22:32     Разобраться с рекурсивной функцией обхода бинарного дерева #2
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void Print(Subscriber * Node)
{
   if(Node != 0)
   {
      Print(Node->left);           
      Print(Node->right);
   }
 
    static int counter;
 
    cout<<counter;
    counter++;
 
    cout  << Node->FIO;
        (strlen (Node->FIO)<24)?cout<<"\t\t": cout<<"\t";
        cout<< Node->YearOfBirth<<"\t"
        << Node->Town<<"\t"
        << Node->Number<<"\t"
        << endl << endl;
    return;
}
Добавлено через 18 минут
чего-то проглядел
C++
1
2
3
4
5
6
7
if(Node != 0)
    {
        Print(Node->left);           
        Print(Node->right);
    }
    else
        return;
Добавлено через 29 минут
смысл в том,что у тебя есть обработчик(Print()) данных для любого "нода". Мы его и вызываем для корневого узла. А у корневого узла есть еще список потомков(идентичных по структуре(!) предку). Почему бы не вызвать для каждого потомка "обработчик данных для любого "нода"? И почему бы этот вызов не зашить в "обработчик для любого нода"? (Print() внутри Print()) А когда оказываешься в потомке, то оказывается и у него есть потомки почему бы не вызвать мега обработчик и для них, к тому же в нем (обработчике) уже зашит хитрый механизм обработки потомков... И так "гоняешься за хвостом", пока не дойдешь до критерия, когда надо вызывать return
C++
1
(if(Node != 0))
, а не Print(). Например потомок-то нулевой и у него не то что своих потомков нет, самого то его нет.

А до того как вызвать return, надо что-нибудь сделать с данными узла. Или что нибудь сделать до обхода потомков, но обязательно до return.

Главное в рекурсии что бы стек не лопнул... А то каждый вызов пихает свои параметры и все без return-а ...
Renji
1617 / 1065 / 259
Регистрация: 05.06.2014
Сообщений: 3,150
12.07.2014, 03:13     Разобраться с рекурсивной функцией обхода бинарного дерева #3
void Tree::Print(Subscriber * Node)
Автор функции - идиот и не знает о this.
Мне нужно к простому выводу данных всего дерева добавить нумерацию списка, но как это сделать в рекурсивной функции не могу понять.
C++
1
2
3
4
5
6
7
8
9
10
int Subscriber::Print(int count=0)
{
    if(!this)
        return count;
    count=left->print(count);
    ++count;
    //сюда вставляется распечатка содержимого узла
    count=right->print(count);
    return count;
}
Faltfromoss
0 / 0 / 0
Регистрация: 28.03.2014
Сообщений: 31
12.07.2014, 07:16  [ТС]     Разобраться с рекурсивной функцией обхода бинарного дерева #4
Цитата Сообщение от Renji Посмотреть сообщение
void Tree::Print(Subscriber * Node)
Автор функции - идиот и не знает о this.
А при чем здесь this, если Print() - это метод класса Tree, а Subscriber * Node - это указатель на структуру с данными, которая является узлом этого дерева. И задача функции выводить не обязательно все дерево, а лишь его часть (ветку), начиная от указанного узла (переданного в функцию Print ()).

И, соответственно этот код:
C++
1
2
3
4
5
6
7
8
9
10
int Subscriber::Print(int count=0)
{
    if(!this)
        return count;
    count=left->print(count);
    ++count;
    //сюда вставляется распечатка содержимого узла
    count=right->print(count);
    return count;
}
немного некорректен в моем случае. В Subscribe нет никаких методов. В ней есть данные и указатели *Parent, *Left, *Right. Всё. А все методы реализованы в классе Tree, который в качестве свойства содержит указатель на корень дерева и от которого все эти методы и пляшут.

to -> olper

Я логику работы вроде бы как и понимаю, не могу понять как отрабатывает код в процессе исполнения. Попробовал отладчиком пошагово отследить, запутался в край :/
Renji
1617 / 1065 / 259
Регистрация: 05.06.2014
Сообщений: 3,150
12.07.2014, 11:57     Разобраться с рекурсивной функцией обхода бинарного дерева #5
В Subscribe нет никаких методов.
Ну так пусть будут. Почему метод работает исключительно с данными Subscribe, но лежит в Tree? "Завистливые функции" - дурной тон.
Я логику работы вроде бы как и понимаю, не могу понять как отрабатывает код в процессе исполнения.
При вызове функции (без разницы Print или еще какой) - пихает локальные переменные Print в стек, туда же кидает адрес кода идущего следом за вызовом функции. После этого передает управление в начало вызванной функции.
При выполнении return - восстанавливает локальные переменные из стека, оттуда-же извлекает данные о том, куда должен передать управление return.
Итого, Node для каждого вызова Print свой собственный, с Node из предыдущих вызовов никак не связанный.

При слишком большой глубине вызова стек неожиданно кончается и программа падает. Но обычно под стек выделяется хотя бы мегабайт, поэтому переполнить его, это надо сильно постараться.
Yandex
Объявления
12.07.2014, 11:57     Разобраться с рекурсивной функцией обхода бинарного дерева
Ответ Создать тему
Опции темы

Текущее время: 06:17. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru