二叉树 - 插入和删除的问题

时间:2016-12-09 21:52:08

标签: c algorithm struct tree

我需要使用方法inorder_tree_walktree_searchtree_minimumtree_successortree_inserttree_delete构建二叉树。当我尝试编译我的程序时,我得到了异常mytree was nullptr。我可能在插入和删除方法方面遇到问题,程序的其他部分工作正常。我根据Cormen写了这段代码。我需要任何建议,谢谢。

#include "stdafx.h"
#include <stdlib.h>

struct tree {
    int key;
    struct tree *parent, *left, *right;
    struct tree *root;
};

void inorder_tree_walk(struct tree *x) {
    if (x != NULL) {
        inorder_tree_walk(x->left);
        printf("%d ", x->key);
        inorder_tree_walk(x->right);
    }
}

struct tree *tree_search(struct tree *x, int key) {
    if (x == NULL || key == x->key)
        return x;
    if (key < (x->key)) {
        return tree_search(x->left, key);
    } else {
        return tree_search(x->right, key);
    }
}

struct tree *tree_minimum(struct tree *x) {
    while (x->left != NULL)
        x = x->left;
    return x;
}

struct tree *tree_successor(struct tree *x) {
    struct tree *y;
    if (x->right != NULL) {
        return tree_minimum(x->right);
    }
    y = x->parent;

    while (y != NULL && x == y->right) {
        x = y;
        y = y->parent;
        return y;
    }
}

struct tree *tree_insert(struct tree *mytree, int key) {
    struct tree *x = NULL;
    struct tree *z = NULL;
    struct tree *y = NULL;

    x = mytree->root;
    while (x != NULL) {
        y = x;
        if (z->key < x->key)
            x = x->left;
        else
            x = x->right;
    }
    z->parent = y;

    if (y == NULL) {
        mytree->root = z;
    } else
    if (z->key < y->key)
        y->left = z;
    else
        y->right = z;
    return 0;
}

struct tree *tree_delete(struct tree *tree, int key) {
    struct tree *z = NULL;
    struct tree *x;
    struct tree *y;

    if (z->left == NULL || z->right == NULL) {
        y = z;
    } else
        y = tree_successor(z);

    if (y->left != NULL)
        x = y->left;
    else 
        x = y->right;

    if (x != NULL)
        x->parent = y->parent;

    if (y->parent = NULL)
        tree->root = x;
    else
    if (y = y->parent->left)
        y->parent->left = x;
    else
        y->parent->right = x;

    if (y != z)
        z->key = y->key;

    return y;
}

int main() {
    tree *root = NULL;
    root = tree_insert(root, 7);
    root = tree_insert(root, 13);
    root = tree_insert(root, 8);
    root = tree_insert(root, 23);
    root = tree_insert(root, -7);
    root = tree_insert(root, 13);
    root = tree_insert(root, 31);
    root = tree_insert(root, 5);
    inorder_tree_walk(root);
    printf("\n\n");

    tree *tmp;
    tmp = tree_minimum(root);
    printf("minimum = %d\n", tmp->key);

    root = tree_delete(root, 8);
    root = tree_delete(root, -7);
    root = tree_delete(root, 31);
    inorder_tree_walk(root);
    printf("\n\n");

    tmp = tree_search(root, 13);
    if (tmp == NULL) {
        printf("not found\n");
    } else {
        printf("found\n");
    }
    getchar();
}

2 个答案:

答案 0 :(得分:2)

功能deserializeUser的{​​{1}}循环中存在问题。您应该从while中取出while块:

tree_successor()

return调用未定义的行为,因为struct tree *tree_successor(struct tree *x) { struct tree *y; if (x->right != NULL) { return tree_minimum(x->right); } y = x->parent; while (y != NULL && x == y->right) { x = y; y = y->parent; } return y; } 在第一个循环中被取消引用时为tree_insert。应使用具有正确键值的新分配节点初始化z

NULL有更多问题,你根本不从根节点走树。

答案 1 :(得分:1)

对于初学者,您应该从结构定义中删除数据成员root

struct tree {
    int key;
    struct tree *parent, *left, *right;
    struct tree *root;
    ^^^^^^^^^^^^^^^^^
};

拥有这样的数据成员是没有意义的。

所以结构看起来像

struct tree {
    int key;
    struct tree *parent, *left, *right;
};

函数tree_insert错误。至少它必须在返回0时返回指向树的根节点的指针。

struct tree *tree_insert(struct tree *mytree, int key) {
    //...
    return 0;
    ^^^^^^^^
}

参数mytree也可以等于NULL但你忽略了这种情况。

我会按照以下方式编写函数

struct tree * tree_insert(struct tree *root, int key)
{
    struct tree *parent = NULL;
    struct tree **current = &root;

    while (*current  != NULL)
    {
        parent = *current;

        if (key < ( *current )->key)
        {
            current = &( *current )->left;
        }
        else
        {
            current = &(*current)->right;
        }
    }

    *current = (struct tree *)malloc(sizeof(struct tree));

    (*current)->key = key;
    (*current)->parent = parent;
    (*current)->left = NULL;
    (*current)->right = NULL;

    return root;
}

使用此功能,您最后可以向树中添加节点并输出树。:)

您的树实施中还有其他错误。但是添加新节点的能力将简化您调试代码的能力。:)

这是一个测试程序

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

struct tree * tree_insert(struct tree *root, int key)
{
    struct tree *parent = NULL;
    struct tree **current = &root;

    while (*current  != NULL)
    {
        parent = *current;

        if (key < ( *current )->key)
        {
            current = &( *current )->left;
        }
        else
        {
            current = &(*current)->right;
        }
    }

    *current = (struct tree *)malloc(sizeof(struct tree));

    (*current)->key = key;
    (*current)->parent = parent;
    (*current)->left = NULL;
    (*current)->right = NULL;

    return root;
}

void inorder_tree_walk( const struct tree *root ) 
{
    if (root != NULL)
    {
        inorder_tree_walk(root->left);
        printf("%d ", root->key);
        inorder_tree_walk(root->right);
    }
}

int main( void )
{
    tree *root = NULL;

    root = tree_insert(root, 7);
    root = tree_insert(root, 13);
    root = tree_insert(root, 8);
    root = tree_insert(root, 23);
    root = tree_insert(root, -7);
    root = tree_insert(root, 13);
    root = tree_insert(root, 31);
    root = tree_insert(root, 5);
    inorder_tree_walk(root);

    printf("\n\n");
}

程序输出

-7 5 7 8 13 13 23 31

它对应于以下树

     7
    /\
   /  \
  /    \
-7      13
 \     / \
  \   /   \
   6 8     23
          / \
         /   \
       13     31