Удаление при балансировке двоичного дерева

У меня есть код для вставки данных в балансирующее двоичное дерево, например, если я ввожу эти входные данные:

20, 10, 30, 5, 15, 25, 4

Я ожидаю, что дерево после ввода будет выглядеть так:

         20
     /        \
    10        30
   /  \     /    \
  5   15   25     4

Итак, при удалении все работает нормально, кроме удаления 4
4 относится к делу 1 в функции Удалить,
Вопрос в том, я не могу понять, почему удаление 4 не работает, но когда я удаляю 5, 15, 25, работает?


Я получил функцию удаления из https://www.youtube.com/watch?v=gcULXE7ViZw
Это для двоичного дерева поиска, но я думал, что это не вызовет проблем, даже если оно используется в двоичном дереве

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<conio.h>

struct node{

    int data, balance;

    struct node *left, *right;

};

int insert(struct node **root, struct node **curr, int data){

    struct node *newNode = (struct node*)malloc(sizeof(struct node));
    newNode -> data = data;
    newNode -> left = NULL;
    newNode -> right = NULL;
    newNode -> balance = 0;

    if((*root) == NULL){
        (*root) = (*curr) = newNode;
        (*root) -> left = NULL;
        (*root) -> right = NULL;
        return 0;
    } else {
        if((*curr)->left == NULL && (*curr)->balance == 0){
            (*curr) -> balance = (*curr) -> balance - 1;
            (*curr) -> left = newNode;
            return 0;
        } else if ((*curr)->right == NULL && (*curr)->balance == -1){
            (*curr) -> balance = (*curr) -> balance + 1;
            (*curr) -> right = newNode;
            return 0;
        } else if ((*curr)->balance == 0 && (*curr)->left->balance == 0){
            (*curr) -> balance = (*curr) -> balance - 1;
            (*curr) = (*curr)->left;
            return insert(root,curr,data);
        } else if ((*curr)->balance < 0 && (*curr)->left->balance < 0){
            (*curr) -> balance = (*curr) -> balance - 1;
            (*curr) = (*curr) -> left;
            return insert(root,curr,data);
        } else if ((*curr)->balance < 0 && (*curr)->left->balance == 0){
            (*curr) -> balance = (*curr) -> balance + 1;
            (*curr) = (*curr)->right;
            return insert(root, curr, data);
        }
    }
}

void preorder(struct node *root){

    if(root == NULL) return;
    printf("%d ", root->data);
    preorder(root->left);
    preorder(root->right);

}

void postorder(struct node *root){

    if(root == NULL) return;
    postorder(root->left);
    postorder(root->right);
    printf("%d ", root->data);

}

void inorder(struct node *root){

    if(root == NULL) return;
    inorder(root->left);
    printf("%d ", root->data);
    inorder(root->right);

}

void search(struct node *root, int *key, int *found){

    if(root == NULL) return;
    search(root->left, key, found);
    if(root->data == *key){
        *found = 1;
        return ;
    }
    search(root->right, key, found);

}

struct node *findMin(struct node *root){

    while(root->left != NULL) root = root->left;
    return root;
}

struct node *Delete(struct node *root, int data){

    if(root == NULL) return root;
    else if(data < root->data) root->left = Delete(root->left, data);
    else if(data > root->data) root->right = Delete(root->right, data);
    else {
        //Case 1: no child / leaf node
        if(root->left == NULL && root->right == NULL){
            free(root);
            root = NULL;
        }
        //Case 2: one child, left or right
        else if(root->left == NULL){
            struct node *temp = root;
            root = root->right;
            free(temp);
        } else if (root->right == NULL){
            struct node *temp = root;
            root = root->left;
            free(temp);
        }
        //Case 3: two children
        else{
            struct node *temp = findMin(root->right);
            root->data = temp->data;
            root->right = Delete(root->right, temp->data);
        }
    }
    return root;
}


int main(){

    struct node *root, *curr;
    int choice, data, key, found, delKey;
    root = curr = NULL;

    while(1){
        found = 0;
        printf("Balanced Binary Tree Menu\n");
        printf("1. Insert Data\n");
        printf("2. View on pre order\n");
        printf("3. View on post order\n");
        printf("4. View on in order\n");
        printf("5. Search\n");
        printf("6. Delete\n");
        printf("7. Exit\n");
        printf("Pilihan: ");scanf("%d", &choice);fflush(stdin);

        if(choice == 1){
            printf("Enter data : "); scanf("%d", &data);
            curr = root;
            insert(&root, &curr, data);
        } else if (choice == 2){
            preorder(root);
            system("pause");
        } else if (choice == 3){
            postorder(root);
            system("pause");
        } else if (choice == 4){
            inorder(root);
            system("pause");
        } else if (choice == 5){
            printf("Search: "); scanf("%d", &key);
            search(root, &key, &found);
            if(found == 1){
                printf("Data found !\n");
            } else {
                printf("Data not found !\n");
            }
            system("pause");
        } else if (choice == 6){
            curr = root;
            printf("Data : ");
            preorder(root);
            printf("\n\n");
            printf("Enter data to be deleted: "); scanf("%d", &delKey);
            Delete(curr, delKey);
            printf("Data after deletion : ");
            preorder(root);
            system("pause");

        } else if (choice == 7){
            return 1;
        }
        system("cls");
    }

    return 0;
}


person Christian Halim    schedule 25.04.2020    source источник
comment
в 20, 10, 30, 5, 15, 4 нет 25, как это может быть в произведенном дереве? insert не возвращает значение во всех случаях. Изменить или удалить сбалансированное дерево должно оставаться сбалансированным, если вы используете другой алгоритм, этого не произойдет. если вставить по порядку 20, 10, 30, 5, 15 и 4 и просмотреть по порядку, то результат будет 5 10 15 20 4 30 что уже неверно, проблема не только в удаляемой части   -  person bruno    schedule 25.04.2020
comment
@bruno о, я забыл написать ввод 25, я собираюсь отредактировать код. Разве результат порядка не левый-родительский-правый, поэтому он печатает правильный результат?   -  person Christian Halim    schedule 25.04.2020
comment
у вас есть предварительный и почтовый заказ, кажется логичным, чтобы порядок производил отсортированное значение нет?   -  person bruno    schedule 25.04.2020
comment
Я намеревался просто распечатать данные в соответствии с деревом, поэтому на самом деле данные не должны быть отсортированы.   -  person Christian Halim    schedule 25.04.2020
comment
как вы можете удалить, если данные упорядочены в дереве, если это не так?   -  person bruno    schedule 25.04.2020
comment
данные удаляются путем поиска по их местоположению в дереве, а затем смотрим дело, есть ли у узла дочерние элементы или нет, но мой поиск, видимо, неверен   -  person Christian Halim    schedule 25.04.2020


Ответы (1)


проблема заключается в функции удаления. вы выполняете удаление как бинарное дерево поиска. Итак, от корневого узла (20 в вашем примере) он переходит к поиску 4 в левых дочерних элементах. поэтому код начинается с 20, идет к 10, затем к 5, а затем останавливается, потому что не находит 4.

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

person Shobhit Kumar    schedule 25.04.2020
comment
Здравствуйте, @Shobhit Kumar. Я попытался использовать неупорядоченный обход и нашел корень, в котором находятся данные. но когда он попытался удалить 4 из моего примера, он показывает результат: 25 10 5 15 4 25 . Можете ли вы объяснить, как посмотреть на каждый узел, когда я хочу удалить? - person Christian Halim; 25.04.2020