Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 5.00/8: Рейтинг темы: голосов - 8, средняя оценка - 5.00
30 / 14 / 7
Регистрация: 08.01.2019
Сообщений: 636
1

Удаление элемента из дерева

06.08.2020, 19:40. Показов 1516. Ответов 13
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Написал удаление, но оно не работает для условия когда удаляемый узел имеет двух наследников. И еще немного не пойму нужно ли рассматривать случай когда этот узел есть корень?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
template<class T>
inline Node<T>* Tree<T>::findMaxNode(Node<T>* node)
{
    while (node->GetRight()) {
        node = node->GetRight();
    }
    return node;
}
template<class T>
inline void Tree<T>::removeNode(Node<T>* delNode)
{
    if (delNode->GetLeft() && delNode->GetRight())
    {
        Node<T>* tmpMax = findMaxNode(delNode->GetLeft());
        delNode->SetData(tmpMax->GetData());
        removeNode(tmpMax);
        return;
    }
        *****
        delete[] delNode;
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
06.08.2020, 19:40
Ответы с готовыми решениями:

удаление элемента бинарного дерева
как удалить элемент бинарного дерева,имеющий 2 потомка?(например дерево (2)-(7 и 0)-(4 и...

Удаление элемента из бинарного дерева
Ругается компилятор в Visual Studio при выполнении кода удаления элемента, а именно в том месте,...

Удаление элемента из сбалансированого бинарного дерева
Задание: написать программу, которая создает сбалансированное бинарное дерево, написать процедуру,...

Реализовать удаление элемента бинарного дерева
Подскажите пожалуйста, нужен метод, который удаляет элемент( и возвращает этот элемент) из...

13
6579 / 4564 / 1843
Регистрация: 07.05.2019
Сообщений: 13,726
06.08.2020, 20:01 2
Цитата Сообщение от Vlast001 Посмотреть сообщение
Написал удаление, но оно не работает для условия когда удаляемый узел имеет двух наследников. И еще немного не пойму нужно ли рассматривать случай когда этот узел есть корень?
C++
1
2
3
4
5
6
7
8
9
10
11
12
template<class T>
inline void Tree<T>::removeNode(Node<T>* delNode)
{
    if (!delNode->GetLeft() && !delNode->GetRight())
        delete[] delNode;
    else
    {
        Node<T>* tmpMax = findMaxNode(delNode->GetLeft());
        delNode->SetData(tmpMax->GetData());
        removeNode(tmpMax);
        return;
    }
И покажи структуру Node, а то что-то трудом могу представить, как можно реализовать removeNode(tmpMax)
0
30 / 14 / 7
Регистрация: 08.01.2019
Сообщений: 636
06.08.2020, 20:08  [ТС] 3
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
И покажи структуру Node
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
template<class T>
class Node
{
    T data;
    Node<T>* left = nullptr;
    Node<T>* right = nullptr;
    Node<T>* parent = nullptr;
public:
    Node(T val);
    T GetData()const;
    Node<T>* GetParent()const;
    Node<T>* GetLeft()const;
    Node<T>* GetRight()const;
    
    void SetData(T val);
    void SetParent(Node<T>* val);
    void SetLeft(Node<T>* val);
    void SetRight(Node<T>* val);
};
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
if (!delNode->GetLeft() && !delNode->GetRight())
        delete[] delNode;
Хм, надеюсь это из-за того, что я показал лишь ту часть удаления которая не работает. В общем вот:
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
template<class T>
inline void Tree<T>::removeNode(Node<T>* delNode)
{
    if (delNode->GetLeft() && delNode->GetRight())
    {
        Node<T>* tmpMax = findMaxNode(delNode->GetLeft());
        delNode->SetData(tmpMax->GetData());
        removeNode(tmpMax);
        return;
    }
    else if (delNode->GetLeft())
    {
        if (delNode == delNode->GetParent()->GetLeft())
        {
            delNode->GetParent()->SetLeft(delNode->GetLeft());
        }
        else
        {
            delNode->GetParent()->SetRight(delNode->GetLeft());
        }
    }
    else if (delNode->GetRight())
    {
        if (delNode == delNode->GetParent()->GetRight())
        {
            delNode->GetParent()->SetLeft(delNode->GetRight());
        }
        else
        {
            delNode->GetParent()->SetLeft(delNode->GetRight());
        }
    }
    else 
    {
        if (delNode == delNode->GetParent()->GetLeft())
        {
            delNode->GetParent()->SetLeft( nullptr);
        }
        else
        {
            delNode->GetParent()->SetRight(nullptr);
        }
    }
    delete[] delNode;
}
Вообще я думал, что удаление можно и без рекурсии, но если и можно я не додумался
P.S.
C++
1
2
3
4
5
6
template<class T>
inline void Tree<T>::remove(T val)
{
    Node<T> * delNode = search(root, val);
    removeNode(delNode);
}
0
6579 / 4564 / 1843
Регистрация: 07.05.2019
Сообщений: 13,726
06.08.2020, 20:35 4
Цитата Сообщение от Vlast001 Посмотреть сообщение
Хм, надеюсь это из-за того, что я показал лишь ту часть удаления которая не работает. В общем вот:
Там не надо больше ничего делать. Если removeNode реализован правильно, то достаточно
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
template<class T>
inline void Tree<T>::removeNode(Node<T>* delNode)
{
    if (!delNode->GetLeft() && !delNode->GetRight())
        removeNode(delNode);
    else
    {
        Node<T>* tmpMax = findMaxNode(delNode->GetLeft());
        delNode->SetData(tmpMax->GetData());
        removeNode(tmpMax);
        return;
    }
}
Добавлено через 5 минут
А вообще, вот так вот - delNode->SetData(tmpMax->GetData()), с деревом не работают. Там данные вообще не обязаны иметь конструкторы копирования/перемещения. Надо менять местами именно ноды, а не копировать их данные.
0
30 / 14 / 7
Регистрация: 08.01.2019
Сообщений: 636
06.08.2020, 20:36  [ТС] 5
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
правильно, то достаточно
Я заглючил, тобишь достаточно этого
C++
1
2
3
4
5
6
7
8
9
if (!delNode->GetLeft() && !delNode->GetRight())
        removeNode(delNode);
    else
    {
        Node<T>* tmpMax = findMaxNode(delNode->GetLeft());
        delNode->SetData(tmpMax->GetData());
        removeNode(tmpMax);
        return;
    }
и больше в методе ничего не нужно? никаких проверок типа else if(delNode->left){}else if(delNode->right){}...?
Я на этом сайте нарисовал свое дерево для визуализации https://www.cs.usfca.edu/~gall... n/BST.html
В общем до меня дошло, что все работало у меня правильно...Просто я накосячкил:
C++
1
2
3
4
5
6
7
8
9
10
else if (delNode->GetRight())
    {
        if (delNode == delNode->GetParent()->GetRight())
        {
            delNode->GetParent()->SetLeft(delNode->GetRight()); // вот, как видите я умудрился дважды SetLeft()написать, а тут SetRight() нужен
        }
        else
        {
            delNode->GetParent()->SetLeft(delNode->GetRight());
        }
Ну все как обычно..)
0
6579 / 4564 / 1843
Регистрация: 07.05.2019
Сообщений: 13,726
06.08.2020, 20:38 6
Цитата Сообщение от Vlast001 Посмотреть сообщение
и больше в методе ничего не нужно? никаких проверок типа else if(delNode->left){}else if(delNode->right){}...?
Ну да. Зачем их проверять, если ты не изменяешь ноду?
0
30 / 14 / 7
Регистрация: 08.01.2019
Сообщений: 636
06.08.2020, 20:50  [ТС] 7
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Надо менять местами именно ноды, а не копировать их данные.
не совсем понял, ну с теорией у меня вроде как лады, а вот реализация..да и когда я изучал как люди реализовывают везде нечто такое вижу: node->data = node2->data; Ну так для примера(я конечно не отрицаю, что не очень много изучал как кто-то это реализовывал)
Так вот
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
если ты не изменяешь ноду
моя реализация терпимо или не оч?) И Вы имеете ввиду, что нужно написать некий Swap()? Но собственно как именно ноды местами поменять в дереве, куда parent`а пихать

Добавлено через 5 минут
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
template<class T>
inline void Tree<T>::removeNode(Node<T>* delNode)
{
    if (!delNode->GetLeft() && !delNode->GetRight())
        removeNode(delNode);
    else
    {
        Node<T>* tmpMax = findMaxNode(delNode->GetLeft());
        delNode->SetData(tmpMax->GetData());
        removeNode(tmpMax);
        return;
    }
}
Я все-таки вставил это и закоментировал все остальное, произошла утечка памяти "с моим любимым кодом":завершает работу с кодом -1073741819.
0
6579 / 4564 / 1843
Регистрация: 07.05.2019
Сообщений: 13,726
06.08.2020, 21:12 8
Цитата Сообщение от Vlast001 Посмотреть сообщение
Я все-таки вставил это и закоментировал все остальное, произошла утечка памяти "с моим любимым кодом":завершает работу с кодом -1073741819.
Я ж вроде написал
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Если removeNode реализован правильно, то достаточно
Цитата Сообщение от Vlast001 Посмотреть сообщение
моя реализация терпимо или не оч?) И Вы имеете ввиду, что нужно написать некий Swap()? Но собственно как именно ноды местами поменять в дереве, куда parent`а пихать
Простейший вариант
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
void ExtractNode(Node<T> *node, Node<T> *newNode = nullptr)
{
    if (!node->parent)
        return;
 
    if (node->parent->left == node)
        node->parent->left = newNode;
    else 
        node->parent->right = newNode;
}
 
template<class T>
void Tree<T>::removeNode(Node<T> *node)
{
    Node<T> *node2 = nullptr;
 
    if (node->right)
        node2 = findMinNode(node->right);
    else if (node->left)
        node2 = findMaxNode(node->left);
 
    if (node2)
    {
        ExtractNode(node2);
        node2->left = node->left;
        node2->right = node->right;
        ExtractNode(node, node2);
    }
 
    delete node;
}
Добавлено через 10 минут
Даже, наверное вот так (в любом случае не проверял)
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
template<class T>
void Tree<T>::removeNode(Node<T> *node)
{
    if (!node->left)
        ExtractNode(node, node->right);
    else if (!node->right)
        ExtractNode(node, node->left);
    else
    {
        auto node2 = findMaxNode(node->left);
        ExtractNode(node2);
        node2->left = node->left;
        node2->right = node->right;
        ExtractNode(node, node2);
    }       
 
    delete node;
}
0
30 / 14 / 7
Регистрация: 08.01.2019
Сообщений: 636
07.08.2020, 15:54  [ТС] 9
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Даже, наверное вот так (в любом случае не проверял)
Не работает))
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
void ExtractNode(Node<T> *node, Node<T> *newNode = nullptr)
{
    if (!node->parent)
        return;
if (node->parent->left == node)
        node->parent->left = newNode;
    else
        node->parent->right = newNode;
}
Я пытался понять чем это отличается от того, что делал я но не понял, Вы просто для того, что я делал написали отдельную функцию

Цитата Сообщение от oleg-m1973 Посмотреть сообщение
delete node;
Вы же имели ввиду delete[] node; ?)
0
6579 / 4564 / 1843
Регистрация: 07.05.2019
Сообщений: 13,726
07.08.2020, 15:55 10
Цитата Сообщение от Vlast001 Посмотреть сообщение
Вы же имели ввиду delete[] node; ?)
Конечно нет. Ты где-то делаешь new Node[N]?
0
30 / 14 / 7
Регистрация: 08.01.2019
Сообщений: 636
07.08.2020, 16:03  [ТС] 11
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Ты где-то делаешь new Node[N]?
Нет, но это же указатель, сейчас я немного в замешательстве. Разве так безопасно?
Когда delete[] node идет очистка всей памяти на которую мог ссылаться указатель, разве будет тоже самое 1 в 1 при delete node?
0
6579 / 4564 / 1843
Регистрация: 07.05.2019
Сообщений: 13,726
07.08.2020, 16:23 12
Цитата Сообщение от Vlast001 Посмотреть сообщение
Когда delete[] node идет очистка всей памяти на которую мог ссылаться указатель, разве будет тоже самое 1 в 1 при delete node?
delete[] нужно вызывать только если ты выделял память при помощи new[]. Иначе просто delete
0
30 / 14 / 7
Регистрация: 08.01.2019
Сообщений: 636
07.08.2020, 16:45  [ТС] 13
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
только если ты выделял память при помощи new[]
Запомню.
Но блин почему это тогда пропускает компилятор да и работает так же? Наверное это великая тайна
0
6579 / 4564 / 1843
Регистрация: 07.05.2019
Сообщений: 13,726
07.08.2020, 16:56 14
Цитата Сообщение от Vlast001 Посмотреть сообщение
Но блин почему это тогда пропускает компилятор да и работает так же? Наверное это великая тайна
Компилятор, в compile-time, тебе ничего и не скажет - откуда он знает как ты выделял указатель, они все одинаковые. А в runtime просто упадёт.

https://wandbox.org/permlink/WmquKlkjieM69n1s
0
07.08.2020, 16:56
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
07.08.2020, 16:56
Помогаю со студенческими работами здесь

Некорректное удаление элемента бинарного дерева поиска
Задача состоит в том, чтобы удалить максимальный в левом поддереве элемент и все его порожденные...

Дополнение списка с обоих концов Удаление элемента из дерева по указанным значением информационную атрибута
Дополнение списка с обоих концов Удаление элемента из дерева по указанным значением информационную...

Вставка элемента в заданную позицию, удаление элемента по заданной позиции, поиск заданного элемента
Добавить в класс &quot;Односвязный список&quot; следующие функции: вставка элемента в заданную позицию,...

Описать класс «множество» (добавление и удаление элемента, пересечение, объединение и удаление множеств )
Описать класс «множество», позволяющий выполнять основные операции – добавление и удаление...

Операции над бинарными деревьями: построение дерева, обход дерева, вставка и удаление элемента дерева
Пожалуйста кто сможет, помогите составить программу: Организация по трудоустройству населения...

Удаление элемента дерева
Всем доброго времени суток. У меня не получается удалить элемент дерева. У меня есть функция,...


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

Или воспользуйтесь поиском по форуму:
14
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru