【问题标题】:Binary tree - problems with insert and delete二叉树 - 插入和删除问题
【发布时间】:2017-04-25 11:12:15
【问题描述】:

我需要使用方法inorder_tree_walk、tree_search、tree_minimum、tree_successor、tree_insert 和tree_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();
}

【问题讨论】:

  • 运行程序时,您在代码中的哪个位置收到异常?
  • 我不知道我的眼睛是不是在欺骗我,但是你怎么能在不调用new、malloc等的情况下动态构建树呢?据我所知,您使用的所有指针都未初始化,这些代码都不应该工作。就好像你错过了关于动态分配的整章。另外,选择一种语言,C 或 C++——它们不一样。
  • 第一次调用tree_insert(),指针root = NULL;和x = mytree-&gt;root;产生异常。而且,该函数返回的唯一值是最后的return 0;。
  • Thomas Cormen 的“算法简介”是一本好书。它不是一本编程书。如果您想学习 C 或 C++(选择一个),请获得一本关于该语言的优秀编程书籍。之后,学习如何实现算法。

标签: c algorithm struct tree


【解决方案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 

【讨论】:

    【解决方案2】:

    函数tree_successor()的while循环有问题。您应该将 return 从 while 块中取出:

    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。 z 应使用具有正确键值的新分配节点进行初始化。

    tree_delete 有更多问题,你根本没有从根节点遍历树。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-10
      • 1970-01-01
      • 2019-08-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多