Бинарное дерево C++. Удаление узла

Функция удаления узла не работает корректно, не получается удалить никакой узел кроме корневого. Функцию добавления узла, удаления узла, организации дерева делал по методичке из универа, прогонял код через gpt и gemini, не помогло.

#include <iostream>
#include <fstream>
#include <string.h>
#include <conio.h>

using namespace std;

const int N = 50;

struct TRAIN 
{
    char order_number[N];
    char train_number[N];
    char departure_point[N];
    char destination_point[N];
    char departure_time[N];
};

struct tree
{
    TRAIN data;
    tree* left;
    tree* right;
};

tree* organizeTree(); // Прототип функции организации дерева
void viewTree(tree* root); // Прототип функции обхода дерева
void showStructure(tree* root, int indent); // Прототип функции просмтора структуры дерева
tree* addNode(tree* root, const TRAIN& newNode); // Прототип функции добавления узла в дерево
tree* deleteNode(tree* root, char order_number[N]); // Прототип функции удаления узла из дерева
void saveTreeToFile(tree* root, ofstream& file); // Прототип функции для сохранения в файл
tree* loadTreeFromFile(ifstream& file); // Прототип функции для загрузки из файла
void freeTree(tree* root); // Прототип функции освобождения выделенной памяти
int getRightmostNodeLevel(tree* root, int level = 0); //Прототип функции поиска самого правого узла
void printTrainsToDestination(tree* root, const char* destination); // Прототип функции печати информации о поездах в выбранном направлении

//Реализация функции добавления узла
tree* addNode(tree* root, const TRAIN& new_node) {
    if (!root)
    {
        root = (tree*)malloc(sizeof(tree));
        if (!root)
        {
            cout << "Не хватает памяти" << endl;
            return NULL;
        }
        root->data = new_node;
        root->left = NULL;
        root->right = NULL;
    }
    else
    {
        if (strcmp(root->data.order_number, new_node.order_number) > 0)
        {
            root->left = addNode(root->left, new_node);
        }
        else
        {
            root->right = addNode(root->right, new_node);
        }
        return root;
    }
}

//Реализация функции удаления узла
tree* deleteNode(tree* node, char order_number[N])
{
    if (node == NULL)
    {
        return node;
    }
    if (strcmp(order_number, node->data.order_number) == 0)
    {
        tree* tmp;
        if (node->right == NULL)
        {
            tmp = node->left;
        }
        else
        {
            tree* ptr = node->right;
            if (ptr->left == NULL)
            {
                ptr->left = node->left;
                tmp = ptr;
            }
            else
            {
                tree* pmin = ptr->left;
                while (pmin->left != NULL)
                {
                    ptr = pmin;
                    pmin = ptr->left;
                }
                ptr->left = pmin->right;
                pmin->left = node->left;
                pmin->right = node->right;
                tmp = pmin;
            }
        }
        delete node;
        return tmp;
    }
    else if (strcmp(order_number, node->data.order_number) < 0)
    {
        node->left = deleteNode(node->left, order_number);
    }
    else
    {
        node->right = deleteNode(node->right, order_number);
    }
    return node;
}




//Функция ввода данных о поезде
TRAIN insertData()
{
    TRAIN train;
    cout << "Введите порядковый номер ";
    cin >> train.order_number;
    cout << "Введите номер поезда ";
    cin >> train.train_number;
    cout << "Введите пункт отправления ";
    cin >> train.departure_point;
    cout << "Введите пункт назначения ";
    cin >> train.destination_point;
    cout << "Введите время отправления ";
    cin >> train.departure_time;
    return train;
}

//Реализация функции организации дерева
tree* organizeTree() {
    tree* root = NULL;
    while (1)
    {
        root = addNode(root, insertData());
        cout << "Хотите продолжить? (выход - 0)\n";
        if (_getch()=='0')
        {
            break;
        }
    }
    return root;
}

//Реализация функции обхода дерева
void viewTree(tree* root)
{
    if (root)
    {
        cout << root->data.order_number << ")" << " Поезд " << root->data.train_number << " в " << root->data.departure_time
            << " отправляется из " << root->data.departure_point << " в " << root->data.destination_point << endl;
        viewTree(root->left);
        viewTree(root->right);
    }
}

//Реализация функции отображения структуры дерева
void showStructure(tree* root, int indent)
{
    if (root)
    {
        indent += 3;
        showStructure(root->right, indent);
        for (int i = 0; i < indent; i++)
        {
            cout << " ";
        }
        cout << root->data.train_number << endl;
        showStructure(root->left, indent);
    }
}

//Реализация функции сохранения в файл
void saveTreeToFile(tree* root, ofstream& file) {
    if (root) {
        file.write((char*)&root->data, sizeof(TRAIN));
        saveTreeToFile(root->left, file);
        saveTreeToFile(root->right, file);
    }
    else {
        // Записываем специальный маркер для обозначения конца ветки
        TRAIN emptyTrain = { "", "", "", "", "" };
        file.write((char*)&emptyTrain, sizeof(TRAIN));
    }
}

//Вспомогательная функция для сохранения в файл
void saveTree(tree* root, const char* filename) {
    ofstream file(filename, ios::binary);
    if (!file) {
        cout << "Не удалось открыть файл для записи." << endl;
        return;
    }
    saveTreeToFile(root, file);
    file.close();
    cout << "Дерево сохранено в файл " << filename << endl;
}

// Реализация функции загрузки из файла
tree* loadTreeFromFile(ifstream& file) {
    TRAIN train;
    if (file.read((char*)&train, sizeof(TRAIN))) {
        // Проверка на конец ветки
        if (strcmp(train.order_number, "") == 0) {
            return NULL;
        }
        tree* root = (tree*)malloc(sizeof(tree));
        if (!root) {
            cout << "Не хватает памяти" << endl;
            return NULL;
        }
        root->data = train;
        root->left = loadTreeFromFile(file);
        root->right = loadTreeFromFile(file);
        return root;
    }
    else {
        return NULL;
    }
}

// Вспомогательная функция для загрузки из файла
tree* loadTree(const char* filename) {
    ifstream file(filename, ios::binary);
    if (!file) {
        cout << "Не удалось открыть файл для чтения." << endl;
        return NULL;
    }
    tree* root = loadTreeFromFile(file);
    file.close();
    cout << "Дерево загружено из файла " << filename << endl;
    return root;
}

// Реализация функции освобождения выделенной памяти
void freeTree(tree* root) {
    if (root) {
        freeTree(root->left);
        freeTree(root->right);
        free(root);
    }
}

// Реализация функции поиска самого правого узла
int getRightmostNodeLevel(tree* root, int level) {
    if (!root) {
        return level - 1;
    }
    int rightLevel = getRightmostNodeLevel(root->right, level + 1);
    return rightLevel;
}

// Реализация функции печати информации о поездах в выбранном направлении
void printTrainsToDestination(tree* root, const char* destination) {
    if (root) {
        if (strcmp(root->data.destination_point, destination) == 0) {
            cout << root->data.order_number << ") Поезд " << root->data.train_number << " в " << root->data.departure_time
                << " отправляется из " << root->data.departure_point << " в " << root->data.destination_point << endl;
        }
        printTrainsToDestination(root->left, destination);
        printTrainsToDestination(root->right, destination);
    }
}

int main() {
    system("chcp 1251");
    tree* root = NULL;
    int choice;
    char filename[N];
    char destination[N];

    do {
        cout << "\nМеню:\n"
            << "1. Организация дерева\n"
            << "2. Просмотр дерева\n"
            << "3. Отображение структуры дерева\n"
            << "4. Добавление узла\n"
            << "5. Удаление узла\n"
            << "6. Сохранить дерево в файл\n"
            << "7. Загрузить дерево из файла\n"
            << "8. Определить уровень самого правого узла\n"
            << "9. Печать поездов по пункту назначения\n"
            << "0. Выход\n"
            << "Ваш выбор: ";
        cin >> choice;
        fflush(stdin);

        switch (choice) 
        {
        case 1:
            root = organizeTree();
            break;
        case 2:
            viewTree(root);
            break;
        case 3:
            showStructure(root, 0);
            break;
        case 4:
            addNode(root, insertData());
            break;
        case 5:
            char temp[N];
            cout << "Введите порядковый номер поезда для удаления: ";
            cin >> temp;
            root = deleteNode(root, temp);
            cout << "Выбранный узел удалён\n";
            break;
        case 6:
            cout << "Введите имя файла для сохранения: ";
            cin >> filename;
            saveTree(root, filename);
            break;
        case 7:
            cout << "Введите имя файла для загрузки: ";
            cin >> filename;
            root = loadTree(filename);
            break;
        case 8:
            if (root) 
            {
                int level = getRightmostNodeLevel(root);
                cout << "Самый правый узел находится на уровне: " << level << endl;
            }
            else 
            {
                cout << "Дерево пусто." << endl;
            }
            break;
        case 9:
            cout << "Введите пункт назначения: ";
            cin >> destination;
            printTrainsToDestination(root, destination);
            break;
        case 0:
            cout << "Выход\n";
            freeTree(root);
            break;
        default:
            cout << "Неправильный выбор. Попробуйте снова.\n";
        }
    } while (choice != 0);
    return 0;
}

Ответы (1 шт):

Автор решения: Lebchik

Попробовал прогнать у себя. Удаление работает со всеми элементами. А вот добавление было поломано: в конструкции switch-case добавь к строке addNode(root, insertData()) получателя результата -- root = addNode(root, insertData()) (иначе root остаётся таким же, каким и был -- NULL'ём).

→ Ссылка