坚持从树中删除节点

时间:2014-09-04 05:10:47

标签: c visual-c++ tree treenode max-heap

我正在尝试使用Visual Studio 2008 v9.0.30729.1 SP在VC ++中构建最大堆。

在树中,每个节点看起来像:

typedef struct node{
    struct data_t *data;
    struct node_t *left;
    struct node_t *right;
}node_t;

单节点创建逻辑如下:

node_t* createNode(int id, int pID, float probability)
{
    node_t *temp = (node_t *)malloc(sizeof(node_t));
    data_t *data = (data_t *)malloc(sizeof(data_t));

    data->id = id;
    data->pID = pID;
    data->probability = probability;

    temp->data = data;
    temp->left = 0;
    temp->right = 0;

    return temp;
}

我已经设法在树中创建和插入元素(插入逻辑工作正常)。我坚持从这棵树中删除节点(准确地说是叶子)的逻辑。

我尝试了四种不同的方法:

node_t* deleteLeaf(node_t* heap)
{
    node_t* leaf;


    if((heap->left==0) && (heap->right==0))
    {
        //heap = 0;     //APROACH 1
        //heap->data = 0;   //APROACH 2

        return heap;
    }
    else if((heap->left!=0) && (heap->right==0))
    {
        leaf = deleteLeaf(heap->left);

    }
    else 
    {
        leaf = deleteLeaf(heap->right);

    }

    //leaf = 0;         //APROACH 3
    //free(leaf);           //APROACH 4 

    return leaf;

}

(取消评估APPROACH 1/2/3/4以获得所需效果)。

这些似乎都不起作用。我需要为前一个节点的左/右指针分配一个零/空值。

如何使这项工作?请帮忙。

3 个答案:

答案 0 :(得分:2)

不要编写4行随机代码并将其称为“方法”,而是尝试实际指定一个有意义的函数。将堆作为参数的函数应该称为DeleteHeap,而不是DeleteLeaf。因为它删除了一个堆,所以它没有任何东西可以返回。那么,你如何删除堆?好吧,如果堆是一个叶子(它没有左或右子树),删除它,否则通过递归调用DeleteHeap删除子树。代码,你已经完成了。

编辑: 你留下了评论:

  

deleteLeaf应该删除树的最后一个元素   最后一级。返回的值应该是包含在中的数据   删除了叶子。

嗯,那是新闻。我们不是读者。你的问题没有说明这一点,功能名称和签名也是错误的。

让我们从名字开始 - DeleteRightmostLeaf。返回类型... data_t*。即使参数类型是错误的......它应该是heap_t**,因为我们必须在指针中存储NULL。

因此,DeleteRightmostLeaf获取指向堆的指针。如果该堆是叶子节点,则在指向它的指针中存储NULL,提取其数据指针,释放节点(按此顺序...否则您将访问已删除的内存,这是不允许的),并返回数据指针。

如果堆不是叶节点,则在指向其最右边子树的指针上递归调用DeleteRightmostLeaf - 如果不是NULL则为右子树,否则为左子树。瞧,你已经完成了。

请注意,在这两种情况下,如果只是想清楚他们需要做什么,那么非常容易来提出答案。

作为奖励,这是一个迭代解决方案。我没有测试甚至编译过这个。

data_t* DeleteRightmostLeaf(node_t** pheap)
{
    node_t* pnode = *pheap;

    if (!pnode)
        return NULL; // empty heap

    while (pnode->left || pnode->right)
    {
        pheap = pnode->right ? &pnode->right : &pnode->left;
        pnode = *pheap;
    }

    *pheap = NULL;
    data_t* pdata = pnode->data;
    free(pnode);
    return pdata;
}

答案 1 :(得分:2)

要删除树中的节点,您需要

  1. 释放内存并为节点执行清理
  2. 修复用于到达节点的指针,使其成为NULL
  3. 第2部分可以通过两种方式解决:

    A)父母进行修复 B)删除例程接收节点地址的地址(额外的间接级别)。

    对于解决方案A,代码只是

    void deleteNodeA(Node *p) {
        if (p) {
            // Here we don't really need part 2 because
            // we're going to destroy the whole node containing
            // the pointers anyway.
            deleteNodeA(p->left);  // add p->left = NULL if you like
            deleteNodeA(p->right); // add p->right = NULL if you like
            free(p->data);
            free(p);
        }
    }
    

    但是调用者需要修复用于到达节点的指针。例如

    Node *p = root, *parent = NULL;
    while (p && (p->left || p->right)) {
        // Not a leaf... go left if possible o right otherwise
        parent = p;
        p = p->left ? p->left : p->right;
    }
    
    // 2: Fix the pointer in parent
    if (parent) {
        if (p == parent->left) {
            parent->left = NULL;
        } else {
            parent->right = NULL;
        }
    } else {
        // No parent... this was the root of the tree
        root = NULL;
    }
    
    deleteNodeA(p);
    

    解决方案B看起来像:

    void deleteNodeB(Node **p) { // Note the double pointer
        if (*p) {
            deleteNode(&((*p)->left));  // Note the &
            deleteNode(&((*p)->right)); // Note the &
            free((*p)->data);
            free(*p);
            *p = NULL; // (2): fixing the pointer
        }
    }
    

    并且例如删除树的叶子的代码是

    Node **p = &root;
    while ((*p) && ((*p)->left || (*p)->right)) {
        // Not a leaf... go left if possible o right otherwise
        p = ((*p)->left) ? &((*p)->left) : &((*p)->right));
    }
    deleteNodeB(p);
    

答案 2 :(得分:1)

尝试修改方法:

node_t* deleteLeaf(node_t* heap)
{
  if (!heap)
    return 0;

  if (heap->left!=0)
    deleteLeaf(heap->left);
  if (heap->right!=0)
    deleteLeaf(heap->right);

  if (heap->data)
    free(heap->data); // free data
  free(heap); // free leaf
  heap = 0;
  return heap;
}

一个问题:此功能应返回哪个值? (现在它总是返回0)。 很难理解你想要做什么(我们没有对功能的描述,预期结果的例子等等)。所以,我怀疑,上面的代码不是解决方案。但这可能是理解问题的第一步。