Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.60/124: Рейтинг темы: голосов - 124, средняя оценка - 4.60
 Аватар для _Eldar_
45 / 30 / 11
Регистрация: 31.10.2009
Сообщений: 200

"Рекурсивная функция" (Обход бинарного дерева)

08.03.2010, 10:40. Показов 27076. Ответов 31
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Привет всем, встретился с такой рекурсивной ф-ей, которая обходит бинарное дерево и выводит его на экран. Не могу понять как она работает
C++
1
2
3
4
5
6
7
8
void print_tree(Node *p, int level){
    if(p){
        print_tree(p->left, level + 1);     // вывод левого поддерева
        for(int i = 0; i < level; i++) cout << "   ";
        cout << p->d << endl;               // вывод корня поддерева
        print_tree(p->right, level + 1);    // вывод левого поддерева
    }
}
первый параметр это указатель на элемент дерева, а второй - уровень на катором находиться узел.
Объясните пожалуйста принцип работы такой функции. Заранее благодарен )

Добавлено через 1 минуту
вот сама структура:
C++
1
2
3
4
5
struct Node{
    int d;
    Node *left;
    Node *right;
};
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
08.03.2010, 10:40
Ответы с готовыми решениями:

Обход бинарного дерева
Прошу Вас, помогите школьнику, незнающему деревья, завтра срочно надо сдать работу, я никак не могу реализовать... 1. В заданном...

Обход бинарного дерева С++
Нужна помощь! Просмотрел много источников, но так и не нашёл своего ответа...Суть задачи состоит в том что, мне нужно при обходе...

Обход Бинарного дерева
Задача: написать функцию, помощью которой можно получить n-тый элемент бинарного дерева по возрастанию. в узлах хранятся целые числа. ...

31
paladin
 Аватар для Yurii_74
286 / 187 / 7
Регистрация: 25.02.2009
Сообщений: 589
10.03.2010, 11:54
Студворк — интернет-сервис помощи студентам
Ну что поделать. Рекурсия в том виде, в котором она реализована (через стек) - не очень замечательная вещь. Динамическое выделение памяти - достаточно простое решение, не требующее колоссальных затрат времени и сил.
Цитата Сообщение от Black Fregat Посмотреть сообщение
Вполне можно представить себе компилятор, убирающий лишние стековые итерации.
Машина не должна быть умнее человека. А то так 2+2 не сможем посчитать однажды. Хотя бы принципы того, как это делается, понимать должны.
Цитата Сообщение от Black Fregat Посмотреть сообщение
Пару гигов на стек
А если у человека не будет этой пары? При нормальном выделении памяти мы можем дойти до того максимума, который позволен на данной конфигурации и вернуться из всего этого, выдав сообщение о том, что смогли дойти дотуда-то.
1
1261 / 799 / 108
Регистрация: 16.09.2009
Сообщений: 2,010
10.03.2010, 12:15
Сообщение от Black Fregat
Пару гигов на стек
Погорячился.


Я где то на форуме видел: создавал кто то массив в 100 000 элементов я точно не помню,
может больше( на один нуль), и компилятор писал Stack Overlow.
Тип элементов был int, пару гигов этот массив не весит точно.
1
Заблокирован
10.03.2010, 12:36
Всем спасибо, один вопрос, что лучше использовать:
То что предложил Genius Ignat или использовать рекурсию, желательно с убедительными аргументами.
0
paladin
 Аватар для Yurii_74
286 / 187 / 7
Регистрация: 25.02.2009
Сообщений: 589
10.03.2010, 12:42
Если глубина рекурсии мала - ее и использовать (для нескольких интов, передаваемых в рекурсивную функцию глубина порядка 10^3 - 10^4, не больше). В противном случае реализовывать хранение промежуточных значений в динамическом стеке.
2
Фрилансер
 Аватар для Black Fregat
3709 / 2083 / 567
Регистрация: 31.05.2009
Сообщений: 6,683
10.03.2010, 13:15
Цитата Сообщение от J_Max Посмотреть сообщение
Всем спасибо, один вопрос, что лучше использовать:
То что предложил Genius Ignat или использовать рекурсию, желательно с убедительными аргументами.
А тут, как всегда, выигрыш одного за счет другого. Рекурсия дает более читабельный код, он быстрее пишется и легче сопровождается. Но он, безусловно, не оптимален, как по расходованию ресурсов, так и по производительности. Если есть необходимость оптимизации по этим параметрам, то раскрывать рекурсию надо однозначно. Причем, вполне возможно, даже глубже, чем сделал Genius Ignat - у него, по сути, та же рекурсия, только замаскированная. Для остальных задач вопрос упирается в стиль программирования, что уже весьма субъективно. И уж однозначно, на мой взгляд, не стоит бороться с рекурсией при острой нехватке времени на разработку.
0
1261 / 799 / 108
Регистрация: 16.09.2009
Сообщений: 2,010
10.03.2010, 14:05
Лучший ответ Сообщение было отмечено как решение

Решение

Вот думал думал, как автору пояснить что такое рекурсия, и сделал
функцию разворота массива: здесь явно показана работа со стеком,
пример факториала я посчитал, что лучше его не показывать.
//--------------------------------------------------------------------
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//Пример рекурсивной функций, разворота массива: работа с аппаратным стеком. 
#include <iostream.h>
void reverse(int *mas,int val,int iter, int otcat_iter);
 
int main(){
 
const int SIZE = 10; 
 
int massive[SIZE] = {1,2,3,4,5,6,7,8,9,0};
 
reverse(massive,massive[0],1,SIZE-1);
 
for(int i=0;i<SIZE;i++)cout<<massive[i];
 
cout<<'\n';
return 0;
}
void reverse(int *mas, int val, int iter, int otcat_iter){
//Точка 1. 
    //----------------------------------------------------
    //Ветвь возрата завершает последнюю вызванную функцию,
    if(otcat_iter==0){
    mas[otcat_iter]=val;
    return;
    }
    //После этого действия: действия будут переходить в точку 2, 
    //----------------------------------------------------
 
reverse(mas, mas[0+iter],iter+1,otcat_iter-1);
 
//Точка 2.
//Это место: есть продолжение дейсвия каждой вызванной функцию,
//после возрата из очередной завершившейся функции.
mas[otcat_iter]=val;  /*этот код будет повторяться: пропорциоанльно количеству вызовов функций-1(одну), значения val и otcat_it
Будут меняться так как мы будет работать с параметрами разных функций.
Да и другие параметры будут меняться.
В эту точку передаётся управления как только очередная вызванная функция завершается.
  */
//-----------------------------------------------------------------------------------
}
Надеюсь мой труд не напрасен.

Добавлено через 28 минут
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
//Более подробное исследование рекурсии: сравнение с аналогом не рекурсией.
void f(int i){
if(i>=5)return;    
f(i+1);    
}
 
/*Поведение  рекурсивной функции  f, можно смоделировать с помощью нескольких функций, но реализация ограничена количеством функции, а рекурсия не зависит от количества функций
*/
void f1(int i);          //эта функция вызывается в main
void f2(int i);          //эта функция вызывается в f1           
void f3(int i);          //эта функция вызывается в f2
void f4(int i);          //эта функция вызывается в f3
void f5(int i);          //эта функция вызывается в f4
void f6(int i);          //эта функция вызывается в f5
//--------------------------------------------------------------------------------------------------------------------------
 
//эта функция вызывается в main
void f1(int i){
if(i>=5)return;
f2(i+1);            //вызываем f2
//После возврата из f2 управление попадёт сюда
 
}
//эта функция вызывается в f1
void f2(int i){
if(i>=5)return;
f3(i+1);            //вызываем f3
//После возврата из f3 управление попадёт сюда
}
//эта функция вызывается в f2
void f3(int i){
if(i>=5)return;
f4(i+1);            //вызываем f4
//После возврата из f4 управление попадёт сюда
}
//эта функция вызывается в f3
void f4(int i){
if(i>=5)return;
f5(i+1);            //вызываем f5
//После возврата из f5 управление попадёт сюда
}
//эта функция вызывается в f4
void f5(int i){
if(i>=5)return ;
f6(i+1);            //вызываем f6
//После возврата из f6 управление попадёт сюда
}
void f6(int i){
if(i>=5)return;
//Эта уже закон, если не указать return вызовы будут бесконечны(пока не переполнится стек), 
//но у нас не рекурсия.
 
}
int main(){
f1(0);
return 0;
}
Как смог так объяснил.
5
Фрилансер
 Аватар для Black Fregat
3709 / 2083 / 567
Регистрация: 31.05.2009
Сообщений: 6,683
10.03.2010, 14:10
Цитата Сообщение от Genius Ignat Посмотреть сообщение
Погорячился. Я где то на форуме видел: создавал кто то массив в 100 000 элементов я точно не помню, может больше( на один нуль), и компилятор писал Stack Overlow.
Тип элементов был int, пару гигов этот массив не весит точно.
Размер стека настраивается.
Значение минимального размера стека может задаваться целым числом в диапазоне между1024 и 2147483647. Значение максимального размера стека должно быть не менее минимального размера и не более 2147483647.
2
1261 / 799 / 108
Регистрация: 16.09.2009
Сообщений: 2,010
10.03.2010, 14:18
А вот ещё пример вывод нескольких значений в обратном поступлению
порядке, за счет стека и параметров.

C++
1
2
3
4
5
6
7
8
void f(int i){
if(i>=10){
cout<<i;
return;
}
f(i+1);
cout<<i;
}
2
paladin
 Аватар для Yurii_74
286 / 187 / 7
Регистрация: 25.02.2009
Сообщений: 589
10.03.2010, 14:21
Цитата Сообщение от Black Fregat Посмотреть сообщение
Размер стека настраивается.
Но память-то под него выделяется при запуске? Оно того стоит? По моему скромному мнению лучше подучить немного прогеров, чем писать настолько неоптимальные решения.
2
Фрилансер
 Аватар для Black Fregat
3709 / 2083 / 567
Регистрация: 31.05.2009
Сообщений: 6,683
10.03.2010, 14:59
Лучший ответ Сообщение было отмечено как решение

Решение

Цитата Сообщение от Yurii_74 Посмотреть сообщение
Но память-то под него выделяется при запуске? Оно того стоит? По моему скромному мнению лучше подучить немного прогеров, чем писать настолько неоптимальные решения.
Было время, когда и отдельные байты экономили. Что-то обязательно приносится в жертву.
3
1261 / 799 / 108
Регистрация: 16.09.2009
Сообщений: 2,010
10.03.2010, 15:28
Так же используется как я её называю завершающая рекурсия которая предназначения для
обмена с функциями через возвращающее значение, и не требующая работы с параметрами
предыдущей вызванной функций после завершения очередной функции, то есть откат к параметрам назад можно не использовать.
Такой тип функций используются допустим в поиске с включением в дереве
или просто в поиске в дереве.

Пример рекурсивная функция, которая не использует "откатанные назад параметры после завершения очередной самой себя функции".

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//Поиск минимального значения в массиве.
#include <stdio.h>
#include <conio.h>
 
#define size 10
int find_min(int *mas, int size_t, int iter , int E_min );
 
 
int main(){
 
int massive[size] = {3,2,3,9,5,6,7,-5,9,-6};
int i;
for(i=0;i<size;i++)printf(" %d",massive[i]);
printf("\n");
 
printf("\n");
printf("min %d ",find_min(massive,size,0,massive[0]));
printf("\n");
 
 
getch();
return 0;
 
 
}
 
int find_min(int *mas,int size_t, int iter, int E_min){
if(mas[iter]<E_min){
    E_min=mas[iter];
}
 
if(iter==size_t-1)return E_min;
//(если наступило условие)делаются возвраты, которые переносят значение.
return find_min(mas,size_t,iter+1,E_min); 
 
}
//Пример рекурсивной функции поиска в дереве:
//Поиск узла рекурсией----------
C++
1
2
3
4
5
6
7
8
9
10
Node *FindR(Node *root , int x){
   //Пока не дойдём до конечной точки или не пока не найден узел------------
   if(root){ 
       
   if(x==root->dan) return root;                        //нашли---------------------
   else if (x<root->dan) return FindR(root->left,x);    //переходим в левое поддерево
   else return FindR(root->right,x);                    //переходим в правое поддерево
   } 
   else return 0;
}
Добавлено через 8 минут
inline перед рекурсивными функциями можно не ставить, так как inline вызовов не будет.
3
Заблокирован
10.03.2010, 15:54
Хороший сайт, и объясняют понятнее и лучше чем в учебнике,
В учебнике буквально три строчки о рекурсии, и примера кроме факториала больше нет, вот так.

Ещё раз спасибо всем, узнал много нового.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
10.03.2010, 15:54

Обход бинарного дерева
может есть у кого такой пример или похожий??или часть какая нибудь?

Обход бинарного дерева в ширину
Я сделал функцию получения следующего узла от заданного узла бинарного дерева(с итератором) согласно обходу в ширину. Возможно эту...

НЕрекурсивный обход бинарного дерева
уважаемые программисты! нужно написать алгоритм обхода бинарного дерева без использования рекурсии, а с помощью стека. Проверить на...

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

Обход бинарного дерева без рекурсии
нужно написать алгоритм обхода бинарного дерева без использования рекурсии, а с помощью стека. Проверить на дереве int, но в самом коде...


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

Или воспользуйтесь поиском по форуму:
32
Ответ Создать тему
Новые блоги и статьи
Транслитерация текста с кириллицы на латиницу
Maks 11.11.2026
Решил облегчить жизнь себе и коллегам админам при создании электронных почтовых ящиков для пользователей, в результате написал обработку "Транслитерация текста" с кириллицы на латиницу, а в ней. . .
Книги по геймдизайну, левел-дизайну, игровым механикам и проектированию игрового опыта
8Observer8 08.11.2026
Содержание блога | English Version 1. 2003 - 06 - Designing Virtual Worlds (1st Edition) Автор: Richard A. Bartle | Объем: 768 стр. Ссылки: Amazon . . .
Родители токсичные абьюзеры по отношению к своим детям ругают их оскорбляют не любят
zorxor 08.11.2026
Жить в атмосфере постоянных оскорблений, критики и холодности со стороны родителей — это тяжелое и болезненное испытание, которое оставляет глубокие эмоциональные раны. Токсичное и абьюзивное. . .
Как только я захожу к себе в свою комнату я сразу же с себя снимаю свои трусы. Ответ от Джемени ИИ.
zorxor 08.11.2026
Джемени, как только я захожу к себе в свою комнату я сразу же с себя снимаю свои трусы. Многие люди, возвращаясь домой, сразу переодеваются в максимально свободную одежду или вовсе предпочитают. . .
Паттерн очереди действий/команд (Action / Command Queue). Система очереди действий и кат-сцен с SDL3 Callbacks, cglm и OpenGL
8Observer8 07.11.2026
Содержание блога | English Version Руководство для начинающих по реализации паттерна очереди действий/ команд (Action / Command Queue) на C++ (C++20) с использованием официального SDL3 Callbacks. . .
Проверка полного ФИО в типовом справочнике
Maks 07.11.2026
Решение реализовано в конфигурации КА2, на примере справочника "КонтактныеЛицаПартнеров". Задача: Запрет инициалов. Не допускаеть использование сокращений вида "И. И. ", "И. И. ", "И И" и. . .
Про "Windows must die!"
kumehtar 04.11.2026
Знаете, чет накатило. . . . Когда-то это было почти боевым кличем: мол, нормальный человек сидит на DOS, OS/ 2 или Linux, а вот это вот - Must Die. А теперь человек произносит «мастдай» с усмешкой - и. . .
Красочные поля с номером страницы svg+background-image
russiannick 04.11.2026
Красочные поля с номером страницы не менее важны чем в эпоху бумажных книг. Посему спешу представить почтеннейшей публике этот важный инструмент который эти поля и формирует. В процессе разработки. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru