C 坚持从树中删除节点
我正在尝试使用Visual Studio 2008 v9.0.30729.1 SP在VC++中构建一个最大堆 在树中,每个节点看起来像: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) {
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
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
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