[英]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.