Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 坚持从树中删除节点_C_Visual C++_Tree_Treenode_Max Heap - Fatal编程技术网

C 坚持从树中删除节点

C 坚持从树中删除节点,c,visual-c++,tree,treenode,max-heap,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; void deleteNodeB(Node **p) { // Note the double pointer if (*p) {

我正在尝试使用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;
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_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;

}
(为达到预期效果,取消注释方法1/2/3/4)

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


如何做到这一点?请提供帮助。

尝试对您的方法进行此修改:

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)。
很难理解您试图做什么(我们没有函数的描述、预期结果的示例等等)。所以,我怀疑,上面的代码不是解决方案。但这可能是了解问题的第一步。

尝试对您的方法进行以下修改:

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)。
很难理解您试图做什么(我们没有函数的描述、预期结果的示例等等)。所以,我怀疑,上面的代码不是解决方案。但这可能是理解这个问题的第一步。

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

编辑: 您留下了评论:

deleteLeaf应该删除树的最后一个元素 最后一关。返回的值应该是 删除叶

嗯,这是新闻。我们不是读心术的人。你的问题没有这样说,函数名和签名也不对

让我们从名字开始--
DeleteRightmostLeaf
。和返回类型<代码>数据*。即使参数类型也是错误的。。。它应该是
heap\u t**
,因为我们必须在指针中存储空值

因此,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;
}

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

编辑: 您留下了评论:

deleteLeaf应该删除树的最后一个元素 最后一关。返回的值应该是 删除叶

嗯,这是新闻。我们不是读心术的人。你的问题没有这样说,函数名和签名也不对

让我们从名字开始--
DeleteRightmostLeaf
。和返回类型<代码>数据*。即使参数类型也是错误的。。。它应该是
heap\u t**
,因为我们必须在指针中存储空值

因此,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;
}

要删除树中的节点,需要

  • 释放内存并对节点执行清理
  • 修复用于到达节点的指针,使其
    NULL
  • 第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看起来像:

    typedef struct node{
        struct data_t *data;
        struct node_t *left;
        struct node_t *right;
    }node_t;
    
    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);
    

    要删除树中的节点,需要

  • 释放内存并对节点执行清理
  • 修复用于到达节点的指针,使其
    NULL
  • 第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);
        }
    }
    
    但是calle