如何在C

时间:2018-11-13 17:02:09

标签: c algorithm search data-structures tree

我正在从文本文件中读取命令。输入示例:

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节点?

2 个答案:

答案 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中处理它们。假设您实现了这两种插入方法之一,让我们看看如何实现在其中任何一种方法中删除节点。

1。将重复项推入右侧或左侧子树(丑陋的解决方案)

如果选择此解决方案,则如果找到具有给定值的节点(我们将其称为值X),则不能保证它不会出现在树的其他位置。您必须在子树之一中搜索值。不仅如此,您还必须传播每个带有值X的节点的深度并选择最深的一个。这需要一些编码。这就是为什么我认为第二种解决方案要好得多。

2。计数值(更好)

根据此方法,每个节点都拥有一个计数器,该计数器告诉给定值出现了多少次。如果要删除此值的一个实例,则如果counter> 1,则只需递减计数器。否则,如果counter == 1,则删除该节点,就像在常规BST中一样。