[英]Creating a Binary Search Tree node with Parent node
我有一个 BST 定义如下:
typedef struct trnode {
Item item;
struct trnode *left;
struct trnode *right;
} Trnode;
typedef struct tree {
Trnode *root;
size_t size;
} Tree;
我遇到的问题通常是我想知道特定树节点的父节点是什么。 定义一个包含父节点的树节点是否很常见,例如:
typedef struct trnode {
Item item;
struct trnode *parent;
struct trnode *left;
struct trnode *right;
} Trnode;
或者是否包括父母不应该做的事情,如果是这样:为什么不呢?
更新:有人要求查看我的删除代码。 这是未经测试的,我很难写(我是 C 的初学者,也只是学习 BST 数据结构)。 无论如何,这里是:
Node * SeekInsertionParent(const Node *root, const Node *pnode)
{
// cmp returns -1 (less than), +1 (greater than), or 0 (equal)
int cmp = CmpNodes(pnode, root);
if (cmp == 0) return NULL; // ignore this for now
Node *child = (cmp < 0)? root->left : root->right;
if (child == NULL)
return root;
else
SeekInsertionParent(child, pnode);
}
Bool DeleteItem(Tree *ptree, const Item *pi)
{
Node *parent;
Node *node = SeekItem(pi, ptree);
if (node == NULL)
return false;
// (1) if no children, then it's a leaf, just delete it
if (!node->left && !node->right) {
free(node);
return true;
}
// (2) if it has one child, link that child to the parent then free the node
if (!node->left || !node->right) {
Node *descendant = (node->left)? node->left : node->right;
descendant->parent = parent;
if (parent->left == node)
parent->left = descendant;
else
parent->right = descendant;
free(node);
}
// (3) if it has two children, then:
// (a) attach the child same-side child to the parent node;
// (b) using the root of the attachment, find the place to insert the other-side child
else {
Node *insert_at, *other_side;
if (parent->left == node) {
node->left->parent = parent;
parent->left = node->left;
other_side = node->right;
} else {
node->right->parent = parent;
parent->right = node->right;
other_side = node->left;
}
free(node);
insert_at = SeekInsertionParent(parent, other_node);
if (insert_at->left == NULL) {
insert_at->left=node;
node->parent=insert_at;
} else {
insert_at->right=node;
node->parent=insert_at;
}
}
return true;
}
通过添加父级,您将添加 O(n) memory,这不是您想要做的,因为大多数时候您的算法将在 O(logN) 中运行。
如果你真的想实现它,你可以简单地找到双 LinkedList的 model 并将其复制到与父级一起构建 BST。
请注意,您可以从XOR Linkedlist中获取灵感,以潜在地解决 memory 盈余问题:
Trnode(current) = Trnode(parent)^Trnode(current->left ^ current->left)
Trnode(current->left) = Trnode(current)^Trnode(current->left->left^current->left->right)
这真的很值得,特别是如果您不需要更改树:
- 从只知道其地址的树中删除一个 Trnode 或
- 当只知道现有节点的地址时,在现有节点之前或之后插入一个新节点。
正如所承诺的,简化版本,使用指针指向。
关键是:您不需要维护父指针,因为它总是可以计算的。 我创建了两个辅助函数来获取指向给定节点(或值)的指针的指针。 插入函数中可以使用相同的辅助函数。
#if 0
#include <stdlib.h>
#include <stdbool.h>
#define Bool bool
#else
typedef enum bool{ false, true} Bool;
void free(void*);
#define NULL (void*) 0
#endif
typedef struct node {
int item;
struct node *left;
struct node *right;
} Node;
// Helper function to find the pointer that points to the node containing item
static Node **node_seek_parent_pp_value(Node **pp, int item)
{
// cmp returns -1 (less than), +1 (greater than), or 0 (equal)
while (*pp) {
int cmp;
cmp = (*pp)->item == item ? 0 : (*pp)->item < item ? 1 : -1;
if (cmp == 0) break; // Found!
pp = (cmp < 0)? &(*pp)->left : &(*pp)->right;
}
return pp;
}
// Same helper function, but with a pointer to item argument
static Node **node_seek_parent_pp_ptr(Node **pp, Node *pnode)
{
if (!pnode) return NULL;
return node_seek_parent_pp_value(pp, pnode->item);
}
Bool DeleteItem(Node **pp, int item)
{
Node *del;
pp = node_seek_parent_pp_value(pp, item);
if (!pp || !*pp) return false; // Not found
// (1) if fewer than two children
if (!(*pp)->left || !(*pp)->right) {
del = *pp;
*pp = del->left ? del->left : del->right;
}
// (2) if it has two children, then:
// (a) detach one child subtree
// (b) insert it onto the other child
// (c) put this other child in place of the node to be deleted.
else {
Node **target, *orphan;
del = *pp;
orphan = del->right;
target = node_seek_parent_pp_ptr(&del->left, orphan);
if (!target) { // should not happen ...
return false;
}
*target = orphan;
*pp = del->left;
}
free(del);
return true;
}
Bool InsertNode(Node **pp, Node * this)
{
pp = node_seek_parent_pp_ptr(pp, this);
if (!pp || *pp) return false; // this is NULL, or already existing
*pp = this; // insert
return true; // Success!
}
您可能想阅读 本文以了解如何在不使用节点表示中的parent
指针的情况下完成删除。 在CLRS中,它给出了
我们可以用一个链接数据结构来表示这样一个二叉搜索树,其中每个节点都是一个 object。 除了键和卫星数据之外,每个节点还包含属性
left
、right
和p
,它们分别指向与其左孩子、右孩子和父节点对应的节点。 如果缺少子项或父项,则相应的属性包含值NIL
。 根节点是树中唯一其父节点为NIL
的节点
他们使用parent
指针,因为它有助于实现诸如delete
、 find-next-larger
、 find-next-smaller
等过程。在代码中使用它不是问题,但是会花费O(n)
额外的 memory 空间。 请记住,如果您不在节点表示中使用parent
指针,那么当您需要需要某些节点的父级的过程时,您需要实现单独的 function 作为参数tree_node
并返回tree_node
的父级。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.