我正在从文本文件中读取命令。输入示例:
Create Key 2
Create Key 1
Create Key 3
Update Key 1
Delete Key 2
我想减少程序执行的操作。例如,创建Key2只是徒劳地删除它。
为了减少操作数量,我决定将这些操作存储在二进制搜索树中。在Cormen,Leiserson,Rivest和Stein撰写的第三本书“算法简介”中,二进制搜索树(BST)被明确定义为允许重复。密钥后的字母代表创建,更新或删除。一个简单的示例如下:
K2(C)
/ \
/ \
K1(C) K3(C) <-- The deepest Key3 appears here.
\ /
K1(U) K2(D) <-- The deepest Key1 and Key2 appear here.
如前所述,我希望能够提取所有唯一键的最深位置,以最大程度地减少操作次数。我在CLRS中找不到对此的任何引用,也许是我在寻找错误的东西。
返回键的简单搜索是不够的,因为它返回找到的第一个节点,因此,宽度优先或深度优先的搜索将不起作用。
struct node* search(struct node* root, int key)
{
// Base Cases: root is null or key is present at root
if (root == NULL || root->key == key)
return root;
// Key is greater than root's key
if (root->key < key)
return search(root->right, key);
// Key is smaller than root's key
return search(root->left, key);
How to handle duplicates in Binary Search Tree?描述了如何处理插入重复项而不是处理提取最后出现的重复项。
另一个想法是返回最正确的唯一键,如下所示:
struct node * maxValueNode(struct node* node)
{
struct node* current = node;
/* loop down to find the rightmost leaf */
while (current->right != NULL)
current = current->right;
return current;
}
我在这里错过了什么吗?如何找到二叉树的最深UNIQUE节点?
答案 0 :(得分:1)
我不明白为什么您需要为此进行BST,但是无论如何,您可以进行搜索,该搜索不会在第一次出现时就停止,并且可以跟踪使用指针找到的最深节点。这应该可以解决问题:
void deepest_search(struct node * root, int key, int currentDepth, int * maxDepth, struct node * deepestNode)
{
// Do nothing if root is null
if (root != NULL)
{
// Update deepest node if needed
if(root->key == key && currentDepth > *maxDepth)
{
*maxDepth = currentDepth;
*deepestNode = *root;
}
// Might need to search both sides because of duplicates
// Can make this an if/else if duplicates are always in left/right subtree
if(root->key <= key)
deepest_search(root->right, key, currentDepth + 1, maxDepth, deepestNode);
if(root->key >= key)
deepest_search(root->left, key, currentDepth + 1, maxDepth, deepestNode);
}
}
我在您的(小)示例中对其进行了测试,并且看来效果很好:
struct node
{
int key;
int val;
struct node *left, *right;
};
void main(void)
{
int key = 1;
int currentDepth = 1;
struct node n5 = {2, 5, NULL, NULL};
struct node n4 = {1, 4, NULL, NULL};
struct node n3 = {3, 3, &n5, NULL};
struct node n2 = {1, 2, NULL, &n4};
struct node n1 = {2, 1, &n2, &n3};
struct node * deepestNode = (struct node *) malloc(sizeof(struct node));
int maxDepth = 0;
deepest_search(&n1, key, currentDepth, &maxDepth, deepestNode);
printf("%d\n", maxDepth);
printf("%d\n", deepestNode->val);
}
答案 1 :(得分:0)
如果您确定要处理重复的值,那么您提到的文章就很好地说明了如何在BST中处理它们。假设您实现了这两种插入方法之一,让我们看看如何实现在其中任何一种方法中删除节点。
如果选择此解决方案,则如果找到具有给定值的节点(我们将其称为值X),则不能保证它不会出现在树的其他位置。您必须在子树之一中搜索值。不仅如此,您还必须传播每个带有值X的节点的深度并选择最深的一个。这需要一些编码。这就是为什么我认为第二种解决方案要好得多。
根据此方法,每个节点都拥有一个计数器,该计数器告诉给定值出现了多少次。如果要删除此值的一个实例,则如果counter> 1,则只需递减计数器。否则,如果counter == 1,则删除该节点,就像在常规BST中一样。