-2
void Bst_DeleteStudent(struct BstStudent** root, char student_name[]){
    struct BstStudent* current = *root;
    struct BstStudent* parent = NULL;
    int flag = 0;
    int i;

    while(current != NULL){
        if(strcmp(current->name, student_name) > 0){
            parent = current;
            current = current->left;
        }
        else if(strcmp(current->name, student_name) < 0){
            parent = current;
            current = current->right;
        }
        else{
            flag = 1;
            //If node has no children
            if(current->left == NULL && current->right == NULL){
                if(parent->left == current){
                    parent->left = NULL;
                }
                else{
                    parent->right = NULL;
                }
                free(current);
                return;
            }
            //If current has one child
            else if((current->left == NULL && current->right != NULL) || (current->left != NULL && current->right == NULL)){
                //If node has a right child 
                if(current->right != NULL && current->left != NULL){
                    if(parent->right == current){
                        parent->right = current->right;
                    }
                    else if(parent->left == current){
                        parent->left = current->right;
                    }
                }
                //If node has a left child
                else if(current->left != NULL && current->right == NULL){
                    if(parent->right == current){
                        parent->right = current->left;
                    }
                    else if(parent->left == current){
                        parent->left = current->left;
                    }
                }
                free(current);
                return;
            }
            //If current has two children
            else{
                struct BstStudent* swap_this = current->right;
                struct BstStudent* swap_this_prev = current;

                while(swap_this->left != NULL){
                    swap_this_prev = swap_this;
                    swap_this = swap_this->left;
                }

                strcpy(current->name, swap_this->name);
                current->id = swap_this->id;
                for(i=0; i<5; i++){
                    current->marks[i] = swap_this->marks[i];
                }

                if(swap_this_prev->left == swap_this){
                    swap_this_prev->left = swap_this->right;
                }
                else if(swap_this_prev->right == swap_this){
                    swap_this_prev->right = swap_this->right;
                }
                free(swap_this);
                return;
            }
        }
    }
    if(flag == 1){
        printf("\nStudent named '%s' removed\n", student_name);
    }
    else{
        printf("\nNo student named '%s' is found in the list!\n", student_name);
    }
}

大家好,我目前想为二叉搜索树实现创建一个删除函数,该函数根据名称按字母顺序对节点进行排序。我的代码工作得很好,大部分时间都可以删除。当我想删除根节点并且根节点只有一个子节点或没有子节点时,该代码仅在特定情况下给出分段错误。其他所有删除都有效。你们能帮帮我吗?

4

2 回答 2

1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

struct BstStudent{
    char name[50];
    int id;
    float marks[5];
    struct BstStudent* left;
    struct BstStudent* right;
};

void Bst_IntroduceStudent(struct BstStudent** root, char student_name[], int student_id){
    struct BstStudent* new_student = (struct BstStudent*)malloc(sizeof(struct BstStudent));
    struct BstStudent* current = *root;
    struct BstStudent* previous = NULL;
    int i;

    strcpy(new_student->name, student_name);
    new_student->id = student_id;
    new_student->left = NULL;
    new_student->right = NULL;
    for(i=0; i<5; i++){
        new_student->marks[i] = 0;
    }

    //Check if the tree is empty
    if(*root == NULL){
        *root = new_student;
    }
    else{
    //If not empty, go through the tree until we find the right spot for the student
    while(current != NULL){
        if(strcmp(current->name, new_student->name) > 0){
            previous = current;
            current = current->left;
        }
        else if(strcmp(current->name, new_student->name) < 0){
            previous = current;
            current = current->right;
        }
        else if(strcmp(current->name, new_student->name) == 0){
            printf("\n** A student with that name already exists! **\n");
            free(new_student);
            return;
        }
    }
    //If we found the right node after which we want to place the student, decide if place right or left
    if(strcmp(previous->name, new_student->name) > 0){
        previous->left = new_student;
    }
    else{
        previous->right = new_student;
    }
}  
}

void Bst_DeleteStudent(struct BstStudent** root, char student_name[]){
    struct BstStudent* current = *root;
    struct BstStudent* parent = NULL;
    int flag = 0;
    int i;

    while(current != NULL){
        if(strcmp(current->name, student_name) > 0){
            parent = current;
            current = current->left;
        }
        else if(strcmp(current->name, student_name) < 0){
            parent = current;
            current = current->right;
        }
        else{
            flag = 1;
            //If node has no children
            if(current->left == NULL && current->right == NULL){
                if(parent->left == current){
                    parent->left = NULL;
                }
                else{
                    parent->right = NULL;
                }
                free(current);
                return;
            }
            //If current has one child
            else if((current->left == NULL && current->right != NULL) || (current->left != NULL && current->right == NULL)){
                //If node has a right child 
                if(current->right != NULL && current->left != NULL){
                    if(parent->right == current){
                        parent->right = current->right;
                    }
                    else if(parent->left == current){
                        parent->left = current->right;
                    }
                }
                //If node has a left child
                else if(current->left != NULL && current->right == NULL){
                    if(parent->right == current){
                        parent->right = current->left;
                    }
                    else if(parent->left == current){
                        parent->left = current->left;
                    }
                }
                free(current);
                return;
            }
            //If current has two children
            else{
                struct BstStudent* swap_this = current->right;
                struct BstStudent* swap_this_prev = current;

                while(swap_this->left != NULL){
                    swap_this_prev = swap_this;
                    swap_this = swap_this->left;
                }

                strcpy(current->name, swap_this->name);
                current->id = swap_this->id;
                for(i=0; i<5; i++){
                    current->marks[i] = swap_this->marks[i];
                }

                if(swap_this_prev->left == swap_this){
                    swap_this_prev->left = swap_this->right;
                }
                else if(swap_this_prev->right == swap_this){
                    swap_this_prev->right = swap_this->right;
                }
                free(swap_this);
                return;
            }
        }
    }
    if(flag == 1){
        printf("\nStudent named '%s' removed\n", student_name);
    }
    else{
        printf("\nNo student named '%s' is found in the list!\n",    student_name);
    }
}

void Bst_Marks(struct BstStudent *student){ 
    printf("Insert the student marks!\n");

    //Declaring variables for looping and inserting marks
    int i;
    float mark;

    //Loop through each module (element) in the marks array and inserting a mark
    for( i=0; i<5; i++){
        printf("Insert the mark for the %d module!\n",i+1);
        scanf("%f",&mark);
        student->marks[i] = mark;
    }
}

void Bst_IntroMarks(struct BstStudent* root, char student_name[]){
    struct BstStudent* current = root;
    int flag = 0;

    while(current != NULL){
        if(strcmp(current->name, student_name) > 0){
            current = current->left;
        }
        else if(strcmp(current->name, student_name) < 0){
            current = current->right;
        }
        else{
            Bst_Marks(current);
            flag = 1;
            break;
        }
    }
    if(flag == 0){
        printf("\nThere is no student named: %s\n", student_name);
    }  
}

void Bst_SearchPrint(struct BstStudent* root, char student_name[]){
    struct BstStudent* current = root;
    int i, flag = 0;

    while(current != NULL){
        if(strcmp(current->name, student_name) > 0){
            current = current->left;
        }
        else if(strcmp(current->name, student_name) < 0){
            current = current->right;
        }
        else{
            printf("\n----------------\n");
            printf("Name:   %s\n", current->name);
            printf("Student ID: %d\n", current->id);
            for(i=0; i<5; i++){
                printf("Module %d:   %f\n", i+1, current->marks[i]);
            }
            flag = 1;
            break;
        }
    }
    if(flag == 0){
        printf("\nThere is no student named: %s\n", student_name);
   }
}

void Bst_PrintAll(struct BstStudent** root){
    struct BstStudent* temp = *root;
    int i;

    if(temp == NULL){
        return;
    }
    else{
        Bst_PrintAll(&temp->left);
        printf("\n----------------\n");
        printf("Name:   %s\n", temp->name);
        printf("Student ID: %d\n", temp->id);
        for(i=0; i<5; i++){
            printf("Module %d:   %f\n", i+1, temp->marks[i]);
        }
        Bst_PrintAll(&temp->right);
    }
}

void leftRotateBinary(struct BstStudent** current){
    struct BstStudent* temp;
    struct BstStudent* original;
    struct BstStudent* right;

    if(*current == NULL || (*current)->right == NULL){
        return;
    }

    original = *current;
    right = original->right;

    temp = (struct BstStudent*)malloc(sizeof(struct BstStudent));
    int i;
    strcpy(temp->name, original->name);
    temp->id = original->id;
    for(i=0; i<5; i++){
        temp->marks[i] = original->marks[i];
    }

    strcpy(original->name,right->name);
    original->id = right->id;
    for(i=0; i<5; i++){
        original->marks[i] = right->marks[i];
    }    

    temp->right = right->left;
    temp->left = original->left;
    original->right = right->right;
    original->left = temp;

    free(right);
}

void rightRotateBinary(struct BstStudent** current){
    struct BstStudent* temp;
    struct BstStudent* original;
    struct BstStudent *left;

    if(*current == NULL || (*current)->left == NULL){
        return;
    }

    original = *current;
    left = original->left;

    temp = (struct BstStudent*)malloc(sizeof(struct BstStudent));
    int i;

    strcpy(temp->name, original->name);
    temp->id = original->id;
    for(i=0; i<5; i++){
        temp->marks[i] = original->marks[i];
    }

    strcpy(original->name, left->name);
    original->id = left->id;
    for(i=0; i<5; i++){
        original->marks[i] = left->marks[i];
    }

    temp->left = left->right;
    temp->right = original->right;
    original->left = left->left;
    original->right = temp;

    free(left);
}

void balanceBinary(struct BstStudent **root){
    struct BstStudent* current = *root;
    int expected, i, odd_node;
    int num_nodes = 0;

    while(current != NULL){
        while(current->left != NULL){
            rightRotateBinary(&current);
        }
        current = current->right;
        num_nodes++;
    } 

    expected = num_nodes - (pow(2,(floor(log2(num_nodes+1)))) - 1);
    current = *root;

    for(i=0; i<expected; i++){
        leftRotateBinary(&current);
        current = current->right;
    }

    current = *root;
    num_nodes = num_nodes - expected;
    odd_node = (num_nodes+1)/2;
    while(odd_node > 1){
        leftRotateBinary(&(*root));

        for(i=0; i<(odd_node-1); i++){
            leftRotateBinary(&(current->right));
            current = current->right;
        }
        odd_node = (odd_node+1)/2;
    }
}



int main(){
//Pointer to root node initially points to empty tree
struct BstStudent* rootPtr = NULL;

    int user_choice;
    char new_name[20], new_name2[20], marks_name[20], report_name[20], delete_name[20];
    int new_ID, new_ID2;

    //Keep displaying the menu until the user decides to quit the program
    do{
        //Main menu
        printf("\nManage data for students: (Type an option and press ENTER)\n");
        printf("1) Introduce new student:\n");
        printf("2) Remove student:\n");
        printf("3) Introduce marks for a student:\n");
        printf("4) Print report for a student:\n");
        printf("5) Print report for all students:\n");
        printf("6) Save to a file:\n");
        printf("7) Retrieve data from a file:\n");
        printf("8) Quit\n\n");

        //Ask the user to choose from the menu options above
        scanf("%d", &user_choice);

        switch(user_choice){
            case 1:
                //Ask the user for the name and ID of student he wants to introduce
                printf("Insert the name of new student: \n");
                scanf("%s", new_name);
                printf("Insert the id of new student: \n");
                scanf("%d", &new_ID);
                Bst_IntroduceStudent(&rootPtr, new_name, new_ID);
                balanceBinary(&rootPtr);
                break;
            case 2:
                printf("Insert the name of student you want to remove: \n");
                scanf("%s", delete_name);
                Bst_DeleteStudent(&rootPtr, delete_name);
                balanceBinary(&rootPtr);
                break;
            case 3:
                printf("Insert the ID of the student you want to introduce marks for!\n");
                scanf("%s", marks_name);
                //Insert the marks
                Bst_IntroMarks(rootPtr, marks_name);
                break;
                break;
            case 4:
                //Ask the user which student's report want to be printed
                printf("Insert the ID of the student you want to print a report!\n");
                scanf("%s", report_name);
                //Print the report for that student
                Bst_SearchPrint(rootPtr, report_name);
                break;
            case 5:
                printf("Print report of all students:\n\n");
                Bst_PrintAll(&rootPtr);
                break;
            case 6:
                break;
            case 7:
                break;
            case 8:
                //Quit the program
                printf("\nProgram ended!\n");
                return 0;
                default:
                break;
        }
    }
    while(user_choice!= 8);
return 0;
}

这是我的整个代码,我不想把它写得太长,但是如果这能给你们更好的上下文来帮助我,我真的很高兴

于 2018-03-20T23:20:43.350 回答
0

在删除根节点的情况下,您正在尝试访问 NULL(parent) 的左/右节点。

在访问 parent 之前添加一个条件,无论 parent 是否为 NULL,如果 parent 不为 NULL,则仅将值分配给其节点指针。

例如

if(parent != NULL) {
    if(parent->left == current){
        parent->left = NULL;
    }
    else{
        parent->right = NULL;
    }
}

在代码的其他部分也添加相同的条件。

于 2018-03-20T20:21:27.463 回答