1 2 3 4 5 6 |
//Листинг #aa Структура, выступающая в роли звена дерева, такими структурами дерево будет заполняться struct Node //Node - Это будет звеном дерева { int x; //x - Число, которое я буду записывать в дерево Node *l,*r; //Адресные поля. Адрес левой части и Адрес правой части (от left,right) }; |
Когда я писал о трёх частях, имел в виду, что запись влево — это одна часть кода, а запись вправо — другая. Вот внутри функции добавления элемента как раз будут использованы все три основные части + кое что ещё. Хватит мне болтать, а то мозг вам, наверное, и без меня выносят. Приступаю к написанию кода.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
//Листинг #1 Структура как основополагающая часть дерева #include <iostream> using namespace std; struct Node //Звено дерева { int x; //То, что записываем в дерево Node *l,*r; //Это указатели на новые звенья }; int main() { Node *Tree = NULL; //Создаю указатель, тип которого = звено дерева и инициализирую его пустотой return 0; } |
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 |
//Листинг #2 Добавляем функцию вывода дерева на экран #include <iostream> using namespace std; struct Node //Звено дерева { int x; //То, что записываем в дерево Node *l,*r; //Это указатели на новые звенья }; void show(Node *&Tree) //Функция обхода { if (Tree != NULL) //Пока не встретится пустое звено { show(Tree->l); //Рекурсивная функция для вывода левого поддерева cout<<Tree->x; //Отображаем корень дерева show(Tree->r); //Рекурсивная функци для вывода правого поддерева } } int main() { Node *Tree = NULL; //Создаю указатель, тип которого = звено дерева и инициализирую его пустотой show(Tree); //Вызов функции обхода дерева; cin.get(); //Обычная задержка перед выходом; return 0; } |
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 |
//Листинг #3 Добавляем функцию добавления в бинарное дерево звена #include <iostream> using namespace std; struct Node //Звено дерева { int x; //То, что записываем в дерево Node *l,*r; //Это указатели на новые звенья }; void show(Node *&Tree) //Функция обхода { if (Tree != NULL) //Пока не встретится пустое звено { show(Tree->l); //Рекурсивная функция для вывода левого поддерева cout<<Tree->x; //Отображаем корень дерева show(Tree->r); //Рекурсивная функции для вывода правого поддерева } } void add_node(int x,Node *&MyTree) //Функция добавления звена в дерево { if (NULL == MyTree) //То, о чем я в самом начале писал. Если дерева нет, то сеем семечко { MyTree = new Node; //Выделяем память под звено дерева MyTree->x = x; //Записываем данные в звено MyTree->l = MyTree->r = NULL; //Подзвенья инициализируем пустотой во избежание ошибок } } int main() { Node *Tree = NULL; //Создаю указатель, тип которого = звено дерева и инициализирую его пустотой for (int i=5; i>0; i--) add_node(i,Tree); //Я решил так заполнять show(Tree); //Обход дерева cin.get(); return 0; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
//Листинг #ba Описание функции добавления звена, (дополняем функцию кодом) void add_node(int x,Node *&MyTree) //Функция добавления звена в дерево { if (NULL == MyTree) //То, о чем я в самом начале писал. Если дерева нет, то сеем семечко { MyTree = new Node; //Выделяем память под звено дерева MyTree->x = x; //Записываем данные в звено MyTree->l = MyTree->r = NULL; //Подзвенья инициализируем пустотой во избежание ошибок } if (x < MyTree->x) //Если нововведенный элемент x меньше чем элемент x из семечка дерева, уходим влево { if (MyTree->l != NULL) add_node(x, MyTree->l); //При помощи рекурсии заталкиваем элемент на свободный участок else //Если элемент получил свой участок, то { MyTree->l = new Node; //Выделяем память левому подзвену. Именно подзвену, а не просто звену MyTree->l->l = MyTree->l->r = NULL; //У левого подзвена будут свои левое и правое подзвенья, инициализируем их пустотой MyTree->l->x = x; //Записываем в левое подзвено записываемый элемент } } } |
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 |
//Листинг #bb Описание функции добавления звена, (дополняем функцию кодом) void add_node(int x,Node *&MyTree) //Функция добавления звена в дерево { if (NULL == MyTree) //То, о чем я в самом начале писал. Если дерева нет, то сеем семечко { MyTree = new Node; //Выделяем память под звено дерева MyTree->x = x; //Записываем данные в звено MyTree->l = MyTree->r = NULL; //Подзвенья инициализируем пустотой во избежание ошибок } if (x < MyTree->x) //Если нововведенный элемент x меньше чем элемент x из семечка дерева, уходим влево { if (MyTree->l != NULL) add_node(x, MyTree->l); //При помощи рекурсии заталкиваем элемент на свободный участок else //Если элемент получил свой участок, то { MyTree->l = new Node; //Выделяем память левому подзвену. Именно подзвену, а не просто звену MyTree->l->l = MyTree->l->r = NULL; //У левого подзвена будут свои левое и правое подзвенья, инициализируем их пустотой MyTree->l->x = x; //Записываем в левое подзвено записываемый элемент } } if (x > MyTree->x) //Если нововведенный элемент x больше чем элемент x из семечка дерева, уходим вправо { if (MyTree->r != NULL) add_node(x, MyTree->r); //При помощи рекурсии заталкиваем элемент на свободный участок else //Если элемент получил свой участок, то { MyTree->r = new Node; //Выделяем память правому подзвену. Именно подзвену, а не просто звену MyTree->r->l = MyTree->r->r = NULL; //У правого подзвена будут свои левое и правое подзвенья, инициализируем их пустотой MyTree->r->x = x; //Записываем в правое подзвено записываемый элемент } } } |
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 58 59 60 61 62 63 64 65 |
//Листинг #4 Бинарное дерево #include <iostream> using namespace std; struct Node //Звено дерева { int x; //То, что записываем в дерево Node *l,*r; //Это указатели на новые звенья }; void show(Node *&Tree) //Функция обхода { if (Tree != NULL) //Пока не встретится пустое звено { show(Tree->l); //Рекурсивная функция для вывода левого поддерева cout << Tree->x; //Отображаем корень дерева show(Tree->r); //Рекурсивная функци для вывода правого поддерева } } void add_node(int x,Node *&MyTree) //Фукция добавления звена в дерево { if (NULL == MyTree) //То, о чем я в самом начале писал. Если дерева нет, то ложим семечко { MyTree = new Node; //Выделяем память под звено дерева MyTree->x = x; //Записываем данные в звено MyTree->l = MyTree->r = NULL; //Подзвенья инициализируем пустотой во избежание ошибок } if (x < MyTree->x) //Если нововведенный элемент x меньше чем элемент x из семечка дерева, уходим влево { if (MyTree->l != NULL) add_node(x,MyTree->l); //При помощи рекурсии заталкиваем элемент на свободный участок else //Если элемент получил свой участок, то { MyTree->l = new Node; //Выделяем память левому подзвену. Именно подзвену, а не просто звену MyTree->l->l = MyTree->l->r = NULL; //У левого подзвена будут свои левое и правое подзвенья, инициализируем их пустотой MyTree->l->x = x; //Записываем в левое подзвено записываемый элемент } } if (x > MyTree->x) //Если нововведенный элемент x больше чем элемент x из семечка дерева, уходим вправо { if (MyTree->r != NULL) add_node(x, MyTree->r); //При помощи рекурсии заталкиваем элемент на свободный участок else //Если элемент получил свой участок, то { MyTree->r = new Node; //Выделяем память правому подзвену. Именно подзвену, а не просто звену MyTree->r->l = MyTree->r->r = NULL; //У правого подзвена будут свои левое и правое подзвенья, инициализируем их пустотой MyTree->r->x = x; //Записываем в правое подзвено записываемый элемент } } } int main() { Node *Tree = NULL; //Создаю указатель, тип которого = звено дерева и инициализирую его пустотой for (int i=5; i>0; i--) add_node(i,Tree); //Это я забивал 5-4-3-2-1, а вывод сами увидите show(Tree); //Вывод на экран дерева. или просто обход дерева cin.get(); return 0; } |
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 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
//Листинг #5 Бинарное дерево, дополняем код функцией для очистки памяти во избежание утечек #include <iostream> using namespace std; struct Node //Звено дерева { int x; //То, что записываем в дерево Node *l,*r; //Это указатели на новые звенья }; void show(Node *&Tree) //Функция обхода { if (Tree != NULL) //Пока не встретится пустое звено { show(Tree->l); //Рекурсивная функция для вывода левого поддерева cout << Tree->x << '\t'; //Отображаем корень дерева show(Tree->r); //Рекурсивная функци для вывода правого поддерева } } /*Добавили очистку памяти*/ void del(Node *&Tree){ if (Tree != NULL) //Пока не встретится пустое звено { del(Tree->l); //Рекурсивная функция прохода по левому поддереву del(Tree->r); //Рекурсивная функци для прохода по правому поддереву delete Tree; //Убиваем конечный элемент дерева Tree = NULL; //Может и не обязательно, но плохого не будет } } void add_node(int x,Node *&MyTree) //Фукция добавления звена в дерево { if (NULL == MyTree) //То, о чем я в самом начале писал. Если дерева нет, то ложим семечко { MyTree = new Node; //Выделяем память под звено дерева MyTree->x = x; //Записываем данные в звено MyTree->l = MyTree->r = NULL; //Подзвенья инициализируем пустотой во избежание ошибок } if (x < MyTree->x) //Если нововведенный элемент x меньше чем элемент x из семечка дерева, уходим влево { if (MyTree->l != NULL) add_node(x, MyTree->l); //При помощи рекурсии заталкиваем элемент на свободный участок else //Если элемент получил свой участок, то { MyTree->l = new Node; //Выделяем память левому подзвену. Именно подзвену, а не просто звену MyTree->l->l = MyTree->l->r = NULL; //У левого подзвена будут свои левое и правое подзвенья, инициализируем их пустотой MyTree->l->x = x; //Записываем в левое подзвено записываемый элемент } } if (x > MyTree->x) //Если нововведенный элемент x больше чем элемент x из семечка дерева, уходим вправо { if (MyTree->r != NULL) add_node(x, MyTree->r); //При помощи рекурсии заталкиваем элемент на свободный участок else //Если элемент получил свой участок, то { MyTree->r = new Node; //Выделяем память правому подзвену. Именно подзвену, а не просто звену MyTree->r->l = MyTree->r->r = NULL; //У правого подзвена будут свои левое и правое подзвенья, инициализируем их пустотой MyTree->r->x = x; //Записываем в правое подзвено записываемый элемент } } } int main() { Node *Tree = NULL; //Создаю указатель, тип которого = звено дерева и инициализирую его пустотой for (int i=5; i>0; i--) add_node(i,Tree); //Это я забивал 5-4-3-2-1, а вывод сами увидите show(Tree); //Вывод на экран дерева. или просто обход дерева cout << '\n'; del(Tree); //Чистка памяти! Распилили дерево for (int i=20; i>5; i--) add_node(i,Tree); //На месте спиленного дерева можно растить новое show(Tree); //Смотрим, что выросло del(Tree); //Когда дерево уже не нужно, зачищаем память } |
А как рекурсивно заполнить N-нарное дерево? Например где структура имеет вид
А чем плохо если код так сократить? У меня вроде как корректно работает. И более читабельно.
немножко код побился, но суть думаю ясна
Вопрос снимается
в этой статье как раз такой код и дан (http://ci-plus-plus-snachala.ru/?p=89)
Все просто, если без &, то в функции ты будешь работать с копией дерева, а если с ним, то передаешь наше дерево и будешь работать всегда с одним и тем же.
😆 😆 😆 😆
А как можно реализовать добавление нового элемента в бинарное дерево без рекурсии ?
Ни как не могу сообразить
Автор, спасибо вам огромное!!! Я над этим деревом бился неделю и понять не мог, а Вы смогли разложить все по полочкам и простым языком. Если не сложно, подскажите, где можно на сайте найти материал по указателям и взятию адреса. Что-то у меня на них очень большие проблемы.
Спасибо вам огромное! Буду разбираться, ибо для меня указатели — темный лес)
в бинарному дереве кроме укзателей левого і правого есть указатель на предидущий елемент, а здесь у вас двосвязний список
а здесь реальное дерево нода которого реализована в виде стуктури с констуктором і деструктором а также клас словарь в котором лежит указатель на само дерево
admin , у меня словарь реализован на дереве, где в качестве ключа английское слово , а в качестве значения перевод. Ну если вы там дерева не видите мне ясен ваш уровень програмрования ❗
Это двусвязный список а не бинарное дерево, в узла дерева должен быть указатель на родительский узел.
Извините, стормозил. Это все таки дерево, а не двусвязных список. У двусвязного списка левый элемент узла Х ссылается обратно на узел Х своим “правым” элементом. И действительно, для дерева ссылка на родительский узел не обязательна.
З.Ы.
Спасибо за ваши труды 🙂
Спасибо за статью. Все супер растолковано, без лишней болтовни. Как раз для новичков.
таки пример изложенный в статье это бинарное дерево или двусвязный список?
Привет! Спасбо за статью. С дереом более-мение, а вот с рекурсией — увы. Читал примеры со степенью и факториалом, а понять так и не смог. Вы случаем не публиковали статью о рекурсии в стиле данного бинарного дерева? Или подскажите, где можно почитатьть про рекурсии, так сказать, для дебилов ? =)
Еще такой вопрос: в вашем примере числа, передаваемые в бинарное дерево, уникальны(от 5 до 1 без повторений). Если числа будут повторятся? При использовании функции rand()?Как тогда помещать значения?
Пример:
Подскажите, а как можно узнать значение самого дальнего элемента по переходам?
Я сейчас не смогу подсказать. Простите уж.
Накопал-таки что-то похожее, работает исправно.
Как только что-то прочитать — я могу, сам рекурсию написать не могу — не тот видимо склад ума(:
Вопрос времени и опыта.
Я давно эту тему описывал и многое не помню. Хотя и сам плохо ориентриовался и сейчас плохо ориентируюсь. Если бы я мог, то подсказал бы обязательно.
Спасибо, что поделились тем, что нашли. Может быть в будущем тоже кому-то пригодится.
Чтобы очистить память надо просто указателю на корень присвоить null
Нет. Так память не чистят. new Только с delete
Здравствуйте а как можно создать копию дерева? И как сделать что бы количество листьев, о которых вы писали, можно было посчитать и вывести это все на экран?
а как с помощью этого дерева определить встречается ли в тексте слово ??
помогите пожалуйста
1. Заполнить дерево словами. Для этого нужно разбить текст на слова и каждое считанное из текста слово добавлять в дерево.
2. Описать дополнительную функцию проверки узла с выбранным словом.
Самая сложная часть — разбиение текста на слова.
Что пробовали, что есть и что не получается?
Помогите пожалуйста, я хочу вывести дерево на экран. Метод заполнения и всего прочего взял ваш.
Точнее чтобы дерево было ввиде дерева на консоли.Заранее спасибо.
// Tree.cpp : Defines the entry point for the console application.
//
#include «stdafx.h»
#include «iostream»
using namespace std;
struct Node
{
int x;//x-Число которое я буду записывать в дерево
Node *left, *right;//Адресные поля на новые звенья
};
void show(Node *Tree)//Функция обхода
{
if (Tree != NULL)//Пока не встретится пустое зерно
{
show(Tree->left);//Рекурсивная функция для вывода левого поддерева//Доступ к члену структуры через указатель.
cout << Tree->x;//Отображаем корень дерева
show(Tree->right); //Рекурсивная функци для вывода правого поддерева
}
}
/*Добавили очистку памяти*/
void del(Node *&Tree)
{
if (Tree != NULL)//Пока не встретится пустое звено
{
del(Tree->left);//Рекурсивная функция прохода по левому поддереву
del(Tree->right);//Рекурсивная функци для прохода по правому поддереву
delete Tree; //Убиваем конечный элемент дерева
Tree = NULL;//Может и не обязательно, но плохого не будет
}
}
void add_node(int x, Node *&MyTree)//Функция добавления звена в дерево
{
if (NULL == MyTree)//Если дерева нет, то сеем семечко
{
MyTree = new Node; //Выделяем память под звено дерева
MyTree->x = x; //Записываем данные в звено
MyTree->left = MyTree->right = NULL;//Подзвенья инициализируем пустотой во избежание ошибок
if (x < MyTree->x)
{
if (MyTree->left != NULL) add_node(x, MyTree->left); //При помощи рекурсии заталкиваем элемент на свободный участок
else
{
MyTree->left = new Node;//Выделяем память левому подзвену. Именно подзвену, а не просто звену
MyTree->left->left = MyTree->left->right = NULL;//У левого подзвена будут свои левое и правое подзвенья, инициализируем их пустотой
MyTree->left->x = x;//Записываем в левое подзвено записываемый элемент
}
if (x > MyTree->x)
{
if (MyTree->right != NULL) add_node(x, MyTree->right);
else
{
MyTree->right = new Node;
MyTree->right->left = MyTree->right->right = NULL;
MyTree->right->x = x;
}
}
}
}
}
int main()
{
int a = 0;
Node *Tree = NULL;//Создаю указатель, тип которого = звено дерева и иницилизирую его пустотой
cout << «Vvedite chislo» << endl;
for (int i = 0; i < 5; i++) {
cin >> a;
add_node(a, Tree);//Я решил так заполнять
}
show(Tree); //Показываем копию
del(Tree); //Чистим память от копии
system(«pause»);
return 0;
}
В комментариях, над вашим вопросом, есть вывод дерева. Вывод не сверху вниз, а вбок.
Сверху вниз сложнее, и в таком виде я помочь не могу.(я не практикуюсь в программировании в последнее время)
Я не знаю как вывести его на экран:(
Отличная статья, спасибо огромное.
Весь инет перерыла чтобы понять что за «постройте дерево» у меня в методичке.
А оказалось все просто.
Долбаеб, у тебя выводит 12345 постоянно, сотри нахуй свой материал!
Долбаеб то тут ты, причем глупый
😎 😎 😎
помогите пожалуйцта, вывести на екран информацию из самого узла бинарного дерева.(рекурсивно,итеративно)
void push(int a, node **t) на предыдущей странице должен быть представлен как *& же, и на этой void show(Node *&Tree) можно записать как *Tree, все равно изменений не производится
Уважаемый автор! Ошибка найдена в листинге! прошу исправить это недоразумение!
В функции добавления элемента в дерево Вы не учитываете того, что вводимые данные могут быть равными!
К примеру, если передать массив из 10 единиц то дерево заполнится всего лишь одной единицей!
Здесь это не ошибка. Точное название описанного дерева «бинарное дерево поиска». Сама архитектура этого дерева такова, что если элемент уже есть, то он не добавляется, поскольку итак понятно, что если элемент есть, то при поиске такой элемент будет найдет. Не имеет смысла добавлять одно и то же, бесполезно увеличивая размер дерева.
АВТОР ДОЛБАЕБ