簡體   English   中英

C語言中如何從AVL二叉樹中正確刪除節點

[英]How to properly delete a node from an AVL Binary Tree in the C language

我正在嘗試用 C 語言對 AVL 二叉樹進行編碼。 我的實現使用一個總體結構來跟蹤二叉樹的長度(即節點數),以及指向根的指針和數據結構的初始狀態。 我已經能夠對一個實現進行編碼,在每次插入時正確地平衡樹。 但是,當我刪除一個節點時,我在平衡樹時遇到了問題。 我正在嘗試使用 GeeksforGeeks ( https://www.geeksforgeeks.org/deletion-in-an-avl-tree/ ) 上列出的示例,但我一直得到不正確的答案。 問題一定在delete_int8_node function,但我看不到哪里。 不幸的是,這個例子很長,因為需要幾個函數來提供一個工作示例。 任何幫助,將不勝感激。

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <stdbool.h>

typedef struct int8_btree {
    int8_t key;
    struct int8_btree *left;
    struct int8_btree *right;
    int height;
} int8_btree;

typedef struct {
    size_t active_length;
    struct int8_btree *root;
    bool status;
} Int8BT

void init_int8_btree(Int8BT *tree) {
    tree->active_length = 0;
    tree->root = NULL;
    tree->status = true;
}
// ================================================================================
// ================================================================================
// NEW_TYPE_NODE (PRIVATE FUNCTIONS)

int8_btree *new_int8_node(int8_t key) {
    struct int8_btree *node = malloc(sizeof(int8_btree));
    if (node == NULL) return node;
    node->key = key;
    node->left = NULL;
    node->right = NULL;
    node->height = 1;
    return node;
}
// ================================================================================
// ================================================================================
// TYPE_NODE_HEIGHT FUNCTIONS (PRIVAT FUNCTIONS)

int int8_node_height(int8_btree *node) {
    if (node == NULL) return 0;
    return node->height;
}
// ================================================================================
// ================================================================================
// MAX_TYPE_NUM FUNCTION (PRIVATE FUNCTIONS)

int max_num(int a, int b) {
    return (a > b)? a : b;
}
// ================================================================================
// ================================================================================
// RIGHT_TYPE_ROTATE FUNCTIONS (PRIVATE FUNCTIONS)

int8_btree *right_int8_rotate(int8_btree * y) {
    struct int8_btree *x = y->left;
    struct int8_btree *T2 = x->right;

    // Perform rotation
    x->right = y;
    y->left = T2;

    x->height = max_num(int8_node_height(y->left), int8_node_height(y->right)) + 1;
    y->height = max_num(int8_node_height(x->left), int8_node_height(x->right)) + 1;
    return x;
}
// ================================================================================
// ================================================================================
// LEFT_STRING_ROTATE FUNCTIONS (PRIVATE FUNCTIONS)

int8_btree *left_int8_rotate(int8_btree *x) {
    struct int8_btree *y = x->right;
    struct int8_btree *T2 = y->left;

    // Perform rotation
    y->left = x;
    x->right = T2;

    x->height = max_num(int8_node_height(x->left), int8_node_height(x->right)) + 1;
    y->height = max_num(int8_node_height(y->left), int8_node_height(y->right)) + 1;
    return y;
}
// ================================================================================
// ================================================================================
// TYPE_NODE_BALANCE FUNCTION (PRIVATE FUNCTIONS)

int int8_node_balance(int8_btree *node) {
    if (node == NULL) return 0;
    return int8_node_height(node->left) - int8_node_height(node->right);
}
// ================================================================================
// ================================================================================
// PUSH_TYPE_BTREE FUNCTION (PRIVATE FUNCTIONS)

int8_btree *insert_int8_btree(int8_btree *node, int8_t key) {
    /* 1.  Perform the normal BST insertion */
    if (node == NULL)
        return new_int8_node(key);

    if (key < node->key)
        node->left  = insert_int8_btree(node->left, key);
    else if (key > node->key)
        node->right = insert_int8_btree(node->right, key);
    else // Equal keys are not allowed in BST
        return node;

    /* 2. Update height of this ancestor node */
    node->height = 1 + max_num(int8_node_height(node->left),
                               int8_node_height(node->right));

    /* 3. Get the balance factor of this ancestor
          node to check whether this node became
          unbalanced */
    short int balance = int8_node_balance(node);

    // If this node becomes unbalanced, then
    // there are 4 cases

    // Left Left Case
    if (balance > 1 && key < node->left->key)
        return right_int8_rotate(node);

    // Right Right Case
    if (balance < -1 && key > node->right->key)
        return left_int8_rotate(node);

    // Left Right Case
    if (balance > 1 && key > node->left->key)
    {
        node->left =  left_int8_rotate(node->left);
        return right_int8_rotate(node);
    }

    // Right Left Case
    if (balance < -1 && key < node->right->key)
    {
        node->right = right_int8_rotate(node->right);
        return left_int8_rotate(node);
    }

    /* return the (unchanged) node pointer */
    return node;
}
// ================================================================================
// ================================================================================
// PUSH_TYPE_BTREE FUNCTIONS

int push_int8_btree(Int8BT *btree, int8_t key) {
    if (btree->status != true) {
        fprintf(stderr, "Binary tree struct not initializex\n");
        return -1;
    }
    btree->root = insert_int8_btree(btree->root, key);
    if (btree->root == NULL) {
        fprintf(stderr, "Malloc failed in file %s on line %d\n", __FILE__, __LINE__);
        return -1;
    }
    btree->active_length += 1;
    return 1;
}
// ================================================================================
// ================================================================================
// FREETYPE_FUNCTIONS (PRIVATE FUNCTIONS)

void freeint8(int8_btree *root) {
    if (root == NULL) return;
    freeint8(root->right);
    freeint8(root->left);
    free(root);
}
// ================================================================================
// ================================================================================
// FREE_TYPE_BTREE FUNCTIONS

void free_int8_btree(Int8BT *btree) {
    if (btree->status != true) {
        fprintf(stderr, "Unitialized binary tree struct cannot be freed\n");
        return;
    }
    freeint8(btree->root);
}
// ================================================================================
// ================================================================================
// MIN_TYPE_NODE (PRIVATE FUNCTIONS)

int8_btree *min_int8_node(int8_btree *root) {
    struct int8_btree *current = root;
    while (current->left != NULL) {
        current = current->left;
    }
    return current;
}
// ================================================================================
// ================================================================================
// DELETE_TYPE_NODE (PRIVATE FUNCTIONS)

int8_btree *delete_int8_node(int8_btree *root, int8_t key) {
    // STEP 1: PERFORM STANDARD BST DELETE

    if (root == NULL)
        return root;

    // If the key to be deleted is smaller than the
    // root's key, then it lies in left subtree
    if ( key < root->key )
        root->left = delete_int8_node(root->left, key);

    // If the key to be deleted is greater than the
    // root's key, then it lies in right subtree
    else if( key > root->key )
        root->right = delete_int8_node(root->right, key);

    // if key is same as root's key, then This is
    // the node to be deleted
    else
    {
        // node with only one child or no child
        if( (root->left == NULL) || (root->right == NULL) )
        {
            struct int8_btree *temp = root->left ? root->left :
                                             root->right;

            // No child case
            if (temp == NULL)
            {
                    temp = root;
                root = NULL;
            }
            else // One child case
             *root = *temp; // Copy the contents of
                            // the non-empty child
            free(temp);
        }
        else
        {
            // node with two children: Get the inorder
            // successor (smallest in the right subtree)
            struct int8_btree* temp = min_int8_node(root->right);

            // Copy the inorder successor's data to this node
            root->key = temp->key;

            // Delete the inorder successor
            root->right = delete_int8_node(root->right, temp->key);
        }
    }

    // If the tree had only one node then return
    if (root == NULL)
      return root;

    // STEP 2: UPDATE HEIGHT OF THE CURRENT NODE
    root->height = 1 + max_num(int8_node_height(root->left),
                               int8_node_height(root->right));

    // STEP 3: GET THE BALANCE FACTOR OF THIS NODE (to
    // check whether this node became unbalanced)
    short int balance = int8_node_balance(root);

    // If this node becomes unbalanced, then there are 4 cases

    // Left Left Case
    if (balance > 1 && int8_node_balance(root->left) >= 0)
        return right_int8_rotate(root);

    // Left Right Case
    if (balance > 1 && int8_node_balance(root->left) < 0)
    {
        root->left =  left_int8_rotate(root->left);
        return right_int8_rotate(root);
    }

    // Right Right Case
    if (balance < -1 && int8_node_balance(root->right) <= 0)
        return left_int8_rotate(root);

    // Right Left Case
    if (balance < -1 && int8_node_balance(root->right) > 0)
    {
        root->right = right_int8_rotate(root->right);
        return left_int8_rotate(root);
    }

    return root;
}
// ================================================================================
// ================================================================================
// POP_TYPE_BTREE FUNCTIONS

void pop_int8_btree(Int8BT *btree, int8_t key) {
    btree->root = delete_int8_node(btree->root, key);
    btree->active_length -= 1;
    //if (btree->status != true) {
    //  fprintf(stderr, "Cannon pop binary tree struct that is not initialized\n");
    //  return;
    //}
    //struct int8_btree *current = btree->root;
    //btree->root = delete_int8_node(btree->root, key);
    //if (btree->root == current && btree->root != NULL) btree->active_length -= 1;
}


void print_preorder(int8_btree *root)
{
    if(root != NULL)
    {
        printf("%d ", root->key);
        print_preorder(root->left);
        print_preorder(root->right);
    }
}
// --------------------------------------------------------------------------------

void print_int8_tree(Int8BT *tree) {
    print_preorder(tree->root);
    printf("\n");
}
// --------------------------------------------------------------------------------

void test_repeat_int8_list(void **state) {
    Int8BT tree;
    init_int8_btree(&tree);
    push_int8_btree(&tree, 9);
    push_int8_btree(&tree, 5);
    push_int8_btree(&tree, 10);
    push_int8_btree(&tree, 0);
    push_int8_btree(&tree, 6);
    push_int8_btree(&tree, 11);
    push_int8_btree(&tree, -1);
    push_int8_btree(&tree, 1);
    push_int8_btree(&tree, 2);

    print_int8_tree(&tree);
    // Correctly prints 9 1 0 -1 5 2 6 10 11
    pop_int8_btree(&tree, 10);
    print_int8_tree(&tree);
    // Incorrectly prints 9 1 0 -1 5 2 6 11
    // Should print 1 0 -1 9 5 2 6 11
    free_int8_btree(&tree);
}

問題不在直接刪除。 是右旋轉function中的深度計算,因此也影響插入。

在那里你翻轉了 x 和 y 深度分配,更正后的版本是:

int8_btree *right_int8_rotate(int8_btree * y) {
    struct int8_btree *x = y->left;
    struct int8_btree *T2 = x->right;

    // Perform rotation
    x->right = y;
    y->left = T2;

    // before it was x->height
    y->height = max_num(int8_node_height(y->left), int8_node_height(y->right)) + 1;
    // before it was y->height
    x->height = max_num(int8_node_height(x->left), int8_node_height(x->right)) + 1;
    return x;
}

一般來說,打印包含深度信息的樹會很有幫助,這樣您就可以在創建后看到不合理的樹。

特別是對於樹,我推薦Graphviz

#include <assert.h>
static void subgraph(const struct int8_btree *const node, FILE *const fp) {
    assert(node && fp);
    fprintf(fp, "\t\tnode%p [label=\"%d:%d\"];\n",
        (const void *)node, node->height, (int)node->key);
    if(node->left) fprintf(fp, "\t\tnode%p -> node%p [arrowhead=rnormal];\n",
        (const void *)node, (const void *)node->left);
    if(node->right) fprintf(fp, "\t\tnode%p -> node%p [arrowhead=lnormal];\n",
        (const void *)node, (const void *)node->right);
    if(node->left) subgraph(node->left, fp);
    if(node->right) subgraph(node->right, fp);
}
static void graph(const Int8BT *const tree, const char *const fn) {
    FILE *fp;
    assert(tree && fn);
    if(!(fp = fopen(fn, "w"))) { perror(fn); return; }
    fprintf(fp, "digraph {\n"
        "\tgraph [truecolor=true, bgcolor=transparent, fontname=modern];\n"
        "\tnode [shape=circle, fontname=modern, "
        "style=filled, fillcolor=Grey95];\n");
    if(!tree->root) fprintf(fp, "empty\n");
    else subgraph(tree->root, fp);
    fprintf(fp, "\tnode [colour=red];\n"
        "}\n");
    fclose(fp);
}

那么你就可以,

    graph(&tree, "tree01.gv");

樹圖。

立即,您可以看出高度沒有感覺。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM