Модераторы: bsa

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> вопрос по бинарному дереву 
V
    Опции темы
yngwie19
Дата 3.6.2010, 08:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 829
Регистрация: 15.6.2008
Где: Новгород

Репутация: нет
Всего: нет



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

#include "stdafx.h"

template <class NODETYPE>
class Tree;

/*Описание класс TreeNode*/
template <class NODETYPE>
class TreeNode
{
    friend Tree<NODETYPE>;
    public:
        TreeNode(const NODETYPE&);
        NODETYPE getData()const;
    private:
        NODETYPE data;
        TreeNode<NODETYPE> *rightPtr, *leftPtr;
};
template <class NODETYPE>
TreeNode<NODETYPE>::TreeNode(const NODETYPE& data)
{
    this->data = data;
    rightPtr = leftPtr = NULL;
}
template <class NODETYPE>
NODETYPE TreeNode<NODETYPE>::getData() const 
{
    return this->data;
}
/*Описание класса Tree*/
template <class NODETYPE>
class Tree
{
    public:
        Tree();
        
        /*Вставка элемента в дерево*/
        void insertNode(const NODETYPE&);
        void insertHelper(TreeNode<NODETYPE> **, const NODETYPE&);
        

    private:
        TreeNode<NODETYPE> *rootPtr;
};
template <class NODETYPE>
Tree<NODETYPE>::Tree()
{
    this->rootPtr = NULL;
}
//---------------------------------------------------------------
template <class NODETYPE>
void Tree<NODETYPE>::insertNode(const NODETYPE& data)
{
    insertHelper(&rootPtr,data);
}
template <class NODETYPE>
void Tree<NODETYPE>::insertHelper(TreeNode<NODETYPE> **ptr, const NODETYPE &data)
{
    if(*ptr == NULL)
        *ptr = new TreeNode<NODETYPE>(data);
    else
    {
        if(data < (*ptr)->getData())
            insertHelper(&((*ptr)->leftPtr),data);
        else if(data > (*ptr)->getData())
            insertHelper(&((*ptr)->rightPtr),data);
        else
            cout<<"элемент "<<(*ptr)->getData()<<" уже содержится в дереве."<<endl;
    }
}
//---------------------------------------------------------------
int _tmain(int argc, _TCHAR* argv[])
{
    setlocale(LC_CTYPE, "Russian_Russia.1251");
    srand(size_t(time(NULL)));
    
    /*Создание объекта бинарное дерево*/
    Tree<int> intTree;
    
    /*Вставка 10 случайных значений в дерево от 1 до 100*/
    for(short i = 0; i<10; i++)
        intTree.insertNode(1 + rand() % 100);



    return 0;
}

Вопрос в следующем, для добавления нового элемента здесь используется функция insertNode(), которая в свою очередь вызывает функцию-утилиту insertHelper(). Этой функции в качестве первого параметра передается указатель на указатель узла дерева (в первом это корень дерева). А можно ли обойтись без функции insertHelper() для рекурсивного добавления нового элемента? Я так понимаю она используется для сохранения указателя на корень дерева? я прав?
PM MAIL   Вверх
xvr
Дата 3.6.2010, 14:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 35
Всего: 223



Обойтись можно, но нужно ли? Процедура вставки узла в дерево рекурсивная, а любая рекурсия должна с чего то начинаться. Для того и сделана функция insertNode - для старта рекурсивного процесса с явно заданного узла (корня)

Можно сделать так:
Код

template <class NODETYPE>
void Tree<NODETYPE>::insertNode(const NODETYPE &data, TreeNode<NODETYPE> **ptr = NULL)
{
    if (!ptr) ptr=&rootPtr;
    if(*ptr == NULL)
        *ptr = new TreeNode<NODETYPE>(data);
    else
    {
        if(data < (*ptr)->getData())
            insertNode(data,&((*ptr)->leftPtr));
        else if(data > (*ptr)->getData())
            insertNode(data,&((*ptr)->rightPtr));
        else
            cout<<"элемент "<<(*ptr)->getData()<<" уже содержится в дереве."<<endl;
    }
}
но пожалуй не нужно  smile 

PM MAIL   Вверх
baldina
Дата 3.6.2010, 16:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 15
Всего: 101



Цитата(xvr @  3.6.2010,  14:28 Найти цитируемый пост)
но пожалуй не нужно  

 smile 

insertNode отвечает за вставку узла в дерево (в определенное дерево *this)
insertHelper отвечает за вставку узла в произвольное поддерево.
две задачи - две функции.

Код

 public:
        void insertHelper(TreeNode<NODETYPE> **, const NODETYPE&);


пожалуй insertHelper лучше сделать private, он кажется лишним в (открытом) интерфейсе класса. его вообще можно сделать статическим или другом класса, т.к. он не работает с this. 
PM MAIL   Вверх
arinamalina
Дата 4.6.2010, 10:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 3
Регистрация: 25.3.2010

Репутация: нет
Всего: нет



а можно полный рабочий код посмотреть?
у меня просто лаба похожаяsmile
PM MAIL   Вверх
yngwie19
Дата 21.10.2010, 17:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 829
Регистрация: 15.6.2008
Где: Новгород

Репутация: нет
Всего: нет



Все-таки скажите пожалуйста зачем здесь использовать **ptr, почему нельзя использовать *ptr.
P.S: когда работал с простыми указателями на переменные и структуры то думал что все понимал, а тут с этими указателями на указатель совсем мозг сломал.
PM MAIL   Вверх
xvr
Дата 21.10.2010, 18:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 35
Всего: 223



Цитата(yngwie19 @  21.10.2010,  17:20 Найти цитируемый пост)
Все-таки скажите пожалуйста зачем здесь использовать **ptr, почему нельзя использовать *ptr.
Потому что этот ptr будет меняться внутри процедуры, и результаты этого изменения должны быть видимы и снаружи процедуры.
 

PM MAIL   Вверх
yngwie19
Дата 21.10.2010, 21:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 829
Регистрация: 15.6.2008
Где: Новгород

Репутация: нет
Всего: нет



xvr, а мы не потеряем таким образом значение rootPtr ?
PM MAIL   Вверх
xvr
Дата 21.10.2010, 21:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 35
Всего: 223



Цитата(yngwie19 @ 21.10.2010,  21:32)
xvr, а мы не потеряем таким образом значение rootPtr ?

Не потеряем, а наоборот - найдем  smile rootPtr должен изменится как минимум раз при вставлении первого узла в пустое дерево (с NULL на указатель на узел)

PM MAIL   Вверх
yngwie19
Дата 22.10.2010, 08:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 829
Регистрация: 15.6.2008
Где: Новгород

Репутация: нет
Всего: нет



xvr, т.е это связано с тем, что когда мы вызываем insertNpdeHelper(rootPtr,data) так, то в эту функцию передается копия адреса, т.е после изменения его в insertNodeHelper() rootPtr также указывать на старое значение (в первом вызове на мусор) ? 
PM MAIL   Вверх
xvr
Дата 22.10.2010, 09:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 35
Всего: 223



Это связанно с тем, что при вставлении узла в пустое дерево вызов insertNpdeHelper(rootPtr,data) должен поменять rootPtr c NULL на data (точнее на TreeNode<NODETYPE>* от data). Если insertNpdeHelper описан как insertNpdeHelper(TreeNode<NODETYPE>* root, ...), то он не сможет поменять свой параметр. Т.е. все присваивания в root так и останутся внутри insertNpdeHelper, а фактический параметр из места вызова (rootPtr) так и останется NULL

PM MAIL   Вверх
yngwie19
Дата 22.10.2010, 09:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 829
Регистрация: 15.6.2008
Где: Новгород

Репутация: нет
Всего: нет



xvr, Спасибо Вам большое за ответ, подскажите пожалуйста почему:

Цитата(xvr @  22.10.2010,  09:19 Найти цитируемый пост)
Если insertNpdeHelper описан как insertNpdeHelper(TreeNode<NODETYPE>* root, ...), то он не сможет поменять свой параметр. Т.е. все присваивания в root так и останутся внутри insertNpdeHelper


PM MAIL   Вверх
xvr
Дата 22.10.2010, 10:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 35
Всего: 223



Цитата(yngwie19 @  22.10.2010,  09:55 Найти цитируемый пост)
подскажите пожалуйста почему:
Потому что в С++ параметры передаются by-value (за исключением параметров типа <type>& - они by-ref). Т.е. при вызове процедуры параметр является локальной переменной процедуры, которую инициализируют значением фактического параметра. Никакие присваивания внутри процедуры этой локальной переменной (формальному параметру процедуры) не влияют на фактический параметр



Это сообщение отредактировал(а) xvr - 22.10.2010, 10:42
PM MAIL   Вверх
baldina
Дата 22.10.2010, 13:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 15
Всего: 101



Цитата(xvr @  22.10.2010,  10:41 Найти цитируемый пост)
за исключением параметров типа <type>& - они by-ref

все параметры by value. передается копия ссылки. прост все ссылки на одно и то же суть синонимы.

yngwie19, не читай мой пост smile

Добавлено @ 13:39
для yngwie19:

в функции С++ параметры передаются по значению (можно интерпретировать как передачу копии), поэтому изменить объект, переданный в качестве параметра, невозможно. но если передавать ссылочные типы - указатели или ссылки - то можно изменить объект, на который они указывают/ссылаются.
поэтому традиционно в С использовалась передача указателя, если нужно было изменить значение. классический пример - scanf()
в С++ появились ссылки, которые синтаксически неотличимы от обычных переменных, но реализованы через указатели, поэтому (как бы) появилась возможность передавать аргументы по ссылке.

ну а если нужно изменить значение указателя, надо передать его адрес, т.е. указатель на указатель:
Код

#include <iostream>
using namespace std;

void foo1 (int a)
{
   ++a;
}
void foo2 (int& a)
{
   ++a;
}
void foo3 (int* pa)
{
   ++*pa;
}
void foo4 (int *p)
{
   p = (int*)0x1234;
}
void foo5 (int **p)
{
   *p = (int*)0x1234;
}
int main ()
{
   int a = 2;
   foo1(a);
   cout << a << endl; // prints 2
   foo2(a);
   cout << a << endl; // prints 3
   foo3(&a);
   cout << a << endl; // prints 4
   int *ptr=0;
   foo4(ptr);
   cout << ptr << endl; // prints 0
   foo5(&ptr);
   cout << ptr << endl; // prints 1234
}




Это сообщение отредактировал(а) baldina - 22.10.2010, 13:42
PM MAIL   Вверх
yngwie19
Дата 22.10.2010, 21:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 829
Регистрация: 15.6.2008
Где: Новгород

Репутация: нет
Всего: нет



Цитата(xvr @  22.10.2010,  10:41 Найти цитируемый пост)
Потому что в С++ параметры передаются by-value 

Правильно ли я понимаю, что если использовать *ptr, то будет происходить утечка памяти, поскольку после выхода из функции insertNodeHelper() переменная ptr уничтожится?
PM MAIL   Вверх
xvr
Дата 23.10.2010, 10:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 35
Всего: 223



Цитата(yngwie19 @ 22.10.2010,  21:29)
Цитата(xvr @  22.10.2010,  10:41 Найти цитируемый пост)
Потому что в С++ параметры передаются by-value 

Правильно ли я понимаю, что если использовать *ptr, то будет происходить утечка памяти, поскольку после выхода из функции insertNodeHelper() переменная ptr уничтожится?

Об утечке памяти можно говорить в программе, которая работает. 'если использовать *ptr' то программа работать не будет, поэтому вопрос об утечках памяти в ней аналогичен вопросу о тяжести заболевания ангиной у трупа  smile 
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0578 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.