我正在尝试使用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以获得所需效果)。
这些似乎都不起作用。我需要为前一个节点的左/右指针分配一个零/空值。
如何使这项工作?请帮忙。
答案 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)
要删除树中的节点,您需要
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看起来像:
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)。 很难理解你想要做什么(我们没有对功能的描述,预期结果的例子等等)。所以,我怀疑,上面的代码不是解决方案。但这可能是理解问题的第一步。