Консультация № 190300
15.12.2016, 19:33
0.00 руб.
0 11 1
Уважаемые эксперты! Пожалуйста, ответьте на вопрос:
Реализуйте класс, представляющий понятие "двоичное дерево поиска". Протестируйте его работу.
Почему 2 функции?
Код:
template <typename T>
void Bintree<T>::insert(Node* &xx, T k) {
Node *z = new Node(k);
if (xx == nullptr) { //если дерева нет то формируем корень
xx = z;
xx->parent = xx->left = xx->right = nullptr;
return;
}
Node *x = xx;
while (x != nullptr) {
if (z->key > x->key) {
if (x->right != nullptr) x = x->right;
else {
z->parent = x;
x->right = z;
break;
}
}
else if (z->key < x->key) {
if (x->left != nullptr) x = x->left;
else {
z->parent = x;
x->left = z;
break;
}
}
}
}


Почему тут 2 функции:

Код:
template <typename T>
void Bintree<T>::insert(T k) {//вставка
insert(head, k);
}

template <typename T>
void Bintree<T>::insert(Node* &xx, T k) {
Node *z = new Node(k);
if (xx == nullptr) { //если дерева нет то формируем корень
xx = z;
xx->parent = xx->left = xx->right = nullptr;
return;
}
Node *x = xx;
while (x != nullptr) {
if (z->key > x->key) {
if (x->right != nullptr) x = x->right;
else {
z->parent = x;
x->right = z;
break;
}
}
else if (z->key < x->key) {
if (x->left != nullptr) x = x->left;
else {
z->parent = x;
x->left = z;
break;
}
}
}
}


и тут:

Код:
template <typename T>
void Bintree<T>::show() {
show(head, 20);
}

template <typename T>//показываем элементы дерева
void Bintree<T>::show(Node* head, int sp) {
if (head == nullptr) return;
show(head->right, sp + 5);
for (int i = 0; i < sp; ++i) std::cout << ' ';
std::cout << head->key << std::endl;
show(head->left, sp + 5);
}


можете объяснить?

Обсуждение

давно
Посетитель
7438
7205
15.12.2016, 20:26
общий
15.12.2016, 20:28
Адресаты:
Почему 2 функции? Ну сделали так Для удобства.
Например, в insert чтобы не задавать явно корень, а только ключ, вызываем первую функцию,
которая вызывает вторую, передавая ей адрес корня и ключ.
В зависимости от реализации, второй способ вызова может быть даже и невозможен, а может и возможен.

В функции show примерно аналогично. При вызове без параметров вызывается вторая
с параметрами по-умолчанию, с указанием корня и количества пробелов, равным 20.
При желании, можно вызывать сразу вторую с явным указанием корня и количества пробелов
(при условии, что есть доступ к корню дерева!).

К слову, в С++ одно и тоже имя функции, но с разными параметрами приводит к двум разным функциям.
Так что, мы имеем по две разные функции...
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
399158
228
15.12.2016, 22:11
общий
а можете рассказать, как происходит вставка у нас? insert
давно
Посетитель
399158
228
16.12.2016, 10:34
общий
Вопрос, почему именно 2 функции, если мы можем в одной сделать все. Какие плюсы и минусы?
давно
Посетитель
7438
7205
16.12.2016, 11:25
общий
Адресаты:
Я скажу больше: на мой взгляд, так делать, в общем-то, неправильно.
1) Становится доступным передача корня, что уже нехорошо;
2) С другой стороны, корень и так доступен, если он определен в данном классе. Нет никакой необходимости передавать его параметром;
3) Для задания параметра со значением по-умолчанию, можно же написать в списке параметров sp=20. И все!
Как не крути, можно все сделать намного проще и надежней!

Я не говорю, что не будет работать. Будет, но "некрасиво". Плюс имеем заложенную мину с некорректной передачей параметром "левого" корня.

Плюсов тут нет вообще. Так было сделано, чтобы вызывать с меньшим числом параметров. Но! Это можно сделать лучше!
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
399158
228
16.12.2016, 11:27
общий
можете написать как?
давно
Посетитель
7438
7205
16.12.2016, 11:29
общий
Адресаты:
А как работает insert, почитайте, как вообще работает двоичное дерево поиска
В Инете все разложено по полочкам. Учитесь работать самостоятельно.
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
7438
7205
16.12.2016, 11:43
общий
Адресаты:
можете написать как?
В течение дня, как будет время, нарисую что-нибудь...
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
399158
228
16.12.2016, 11:48
общий
спасибо
давно
Посетитель
7438
7205
16.12.2016, 13:25
общий
16.12.2016, 13:26
Адресаты:
Вот Вам программа.
Некоторое уточнение к предыдущему.
В данной программе для вывода используется рекурсия, поэтому задавать текущий узел параметром
необходимо, но тогда вызываемую функцию с параметрами необходимо определить, как private
Как и удаление дерева...
Для вставки передавать корень параметром необходимости нет.
Кое-что подправил, прокомментировал
[code h=200]
#include <iostream>

using namespace std;

#define nullptr 0

struct Node
{
int key;
Node *left;
Node *right;
Node *parent;
};

template<class T>
class Bintree
{
public:
//конструктор
Bintree<T>(){head = nullptr;};

//деструктор
~Bintree(void);

//вставка
void insert(T k);

//вывод
void show(int sp=20);

private:
Node* head;
void FreeNode(Node *node);
void show(Node *node, int sp);
};

template<class T>
void Bintree<T>::FreeNode(Node *node)
{
if (node)
{
Bintree::FreeNode(node->left); //левого потомка
Bintree::FreeNode(node->right); //правого потомка
delete node; //память самого узла
}
}

template<class T>
Bintree<T>::~Bintree()
{
Bintree<T>::FreeNode(head);
}

template <typename T>
void Bintree<T>::insert(T k)
{
Node *z = new Node; //создаем новый узел
z->key = k; //ключ
z->left = z->right = nullptr; //обнулим указатели на потомков

if (head == nullptr) //был ли корень?
{ //если дерева нет то формируем корень
z->parent = nullptr; //у корня родителя нет
head = z; //сохраним как корень
}
else
{
Node *x = head; //начинаем обход с корня
while (1) //по всем узлам
{
if (z->key > x->key) //если ключ нового узла больше текущего
{
if (x->right != nullptr)//и если правый потомок непустой
x = x->right; //то правого потомка делаем текущим
else
{ //правый пустой
z->parent = x; //текущий для нового будет родителем
x->right = z; //а правым потомком текущего станет новый
break; //новый узел вставлен в дерево - выходим из цикла
}
}
else if (z->key < x->key) //если ключ нового узла меньше текущего
{
if (x->left != nullptr) //и левый потомок непустой
x = x->left; //то левого потомка делаем текущим
else
{ //левый пустой
z->parent = x; //текущий для нового будет родителем
x->left = z; //а левым потомком текущего станет новый
break; //новый узел вставлен в дерево - выходим из цикла
}
}
else
{
delete z; //если равно, то удалим созданный узел (игнорируем!)
break; //и выходим из цикла
}
}
}
}

template <typename T> //показываем элементы дерева
void Bintree<T>::show(int sp)
{
Bintree<T>::show(head, sp);
}

template <typename T> //показываем элементы дерева
void Bintree<T>::show(Node *node, int sp=20)
{
if (node == nullptr)
return;
show(node->right, sp + 5);
for (int i = 0; i < sp; ++i) cout << ' ';
cout << node->key << endl;
show(node->left, sp + 5);
}

int main()
{
Bintree<int> tree; //создаем класс
tree.insert(5); //вставим несколько узлов
tree.insert(3);
tree.insert(7);
tree.insert(6);
tree.show(); //выведем с позиции 20 (по умолчанию)
tree.insert(4); //добавим еще несколько узлов
tree.insert(8);
tree.show(0); //выведем с 0 позиции
tree.insert(8); //пытаемся добавить узел с существующим ключом
tree.show(0); //выводим
return 0;
}
[/code]
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
399158
228
16.12.2016, 13:32
общий
понял, спасибо. да, все таки там запутанный вариант...
давно
Посетитель
7438
7205
16.12.2016, 13:50
общий
это ответ
Здравствуйте, Посетитель - 399158!
Вот Вам программа на основе приведенного кода.
В данной программе для вывода используется рекурсия, поэтому задавать текущий узел параметром
необходимо, но тогда вызываемую функцию с параметрами необходимо определить, как private
Удаление дерева тоже реализовано рекурсивно, поэтому сделано аналогично

Для вставки передавать корень параметром необходимости нет.
Показано, как задавать параметр по-умолчанию.
Кое-что подправил, прокомментировал
[code h=200]
#include <iostream>

using namespace std;

#define nullptr 0

struct Node
{
int key;
Node *left;
Node *right;
Node *parent;
};

template<class T>
class Bintree
{
public:
//конструктор
Bintree<T>(){head = nullptr;};

//деструктор
~Bintree(void);

//вставка
void insert(T k);

//вывод
void show(int sp=20);

private:
Node* head;
void FreeNode(Node *node);
void show(Node *node, int sp);
};

template<class T>
void Bintree<T>::FreeNode(Node *node)
{
if (node)
{
Bintree::FreeNode(node->left); //левого потомка
Bintree::FreeNode(node->right); //правого потомка
delete node; //память самого узла
}
}

template<class T>
Bintree<T>::~Bintree()
{
Bintree<T>::FreeNode(head);
}

template <typename T>
void Bintree<T>::insert(T k)
{
Node *z = new Node; //создаем новый узел
z->key = k; //ключ
z->left = z->right = nullptr; //обнулим указатели на потомков

if (head == nullptr) //был ли корень?
{ //если дерева нет то формируем корень
z->parent = nullptr; //у корня родителя нет
head = z; //сохраним как корень
}
else
{
Node *x = head; //начинаем обход с корня
while (1) //по всем узлам
{
if (z->key > x->key) //если ключ нового узла больше текущего
{
if (x->right != nullptr)//и если правый потомок непустой
x = x->right; //то правого потомка делаем текущим
else
{ //правый пустой
z->parent = x; //текущий для нового будет родителем
x->right = z; //а правым потомком текущего станет новый
break; //новый узел вставлен в дерево - выходим из цикла
}
}
else if (z->key < x->key) //если ключ нового узла меньше текущего
{
if (x->left != nullptr) //и левый потомок непустой
x = x->left; //то левого потомка делаем текущим
else
{ //левый пустой
z->parent = x; //текущий для нового будет родителем
x->left = z; //а левым потомком текущего станет новый
break; //новый узел вставлен в дерево - выходим из цикла
}
}
else
{
delete z; //если равно, то удалим созданный узел (игнорируем!)
break; //и выходим из цикла
}
}
}
}

template <typename T> //показываем элементы дерева
void Bintree<T>::show(int sp)
{
Bintree<T>::show(head, sp);
}

template <typename T> //показываем элементы дерева
void Bintree<T>::show(Node *node, int sp=20)
{
if (node == nullptr)
return;
show(node->right, sp + 5);
for (int i = 0; i < sp; ++i) cout << ' ';
cout << node->key << endl;
show(node->left, sp + 5);
}

int main()
{
Bintree<int> tree; //создаем класс
tree.insert(5); //вставим несколько узлов
tree.insert(3);
tree.insert(7);
tree.insert(6);
tree.show(); //выведем с позиции 20 (по умолчанию)
tree.insert(4); //добавим еще несколько узлов
tree.insert(8);
tree.show(0); //выведем с 0 позиции
tree.insert(8); //пытаемся добавить узел с существующим ключом
tree.show(0); //выводим
return 0;
}
[/code]
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Форма ответа