【问题标题】:Find the first key bigger than X on Binary Search Tree在二叉搜索树上找到大于 X 的第一个键
【发布时间】:2015-07-04 23:06:21
【问题描述】:

BST 中元素的后继者是该元素在 BST 中的后继者 由中序遍历确定的排序顺序。寻找 当每个节点都有一个指向其父节点的指针时出现后继 在 CLRS 的算法教科书中(麻省理工学院的算法简介 按)。

如果结构中没有parent,有没有办法找到大于 X 的第一个值?喜欢:

typedef struct tree tree;
struct tree{
   int value;
   tree *left;
   tree *right;
};

//Function:  

tree *find_first_bigger(tree *t, int x){}  

我尝试过使用:

tree *find_first_bigger(tree *t, int x){
   if(t == NULL)
      return NULL;

   if((*t)->value > x)
      find_first_bigger((*t)->left, x);

   else if((*t)->value < x)
      find_first_bigger((*t)->right), x);
   else if((*t)->value == x){
      if((*t)->right != NULL) 
         return tree_first_bigger((*t)->right);
      else
         return tree;
   }
}  

在这个例子中(它使用字母,但没有问题),如果我尝试搜索大于N的第一个(它应该返回我O)但它返回我N

【问题讨论】:

  • 我认为您应该为该递归函数放置基本情况(如果当前节点为空),以便在树中没有比 X 更大的键时停止。您还应该检查是否找到了密钥并将其归还。
  • @PlayHardGoPro 不要担心被否决,我的解决方案是 100% 正确的。

标签: c algorithm binary-search-tree


【解决方案1】:

你已经完成了 90% 的工作。请允许我完成剩下的 10%。

由于 t 是一个指向结构的指针,你应该使用 t->left 而不是 (*t)->left 并且在访问 right 和 value 结构的字段。

现在,只需将您的函数修改为:

将此添加为函数的第一行

static tree* PTR=NULL;

将第二个if条件修改为

if(t->value > x)
 {
     PTR=t;
     find_first_bigger(t->left, x);
 }

将第二个else if条件修改为:

else if(t->value == x)
{
  if(t->right != NULL)
     {
         t=t->right;
         while(t->left!=NULL)
            t=t->left;
         return t;
     }
  else return PTR;
}

因此正确的函数是

tree *find_first_bigger(tree *t, int x)
{
   static tree* PTR=NULL;
   if(t == NULL)
      return NULL;
   if(t->value > x)
     {
         PTR=t;
         find_first_bigger(t->left, x);
     }
   else if(t->value < x)
       find_first_bigger(t->right, x);
   else if(t->value == x)
    {
      if(t->right != NULL)
         {
             t=t->right;
             while(t->left!=NULL)
                t=t->left;
             return t;
         }
      else return PTR;
   }
}

在主函数中,如果返回的指针为NULL,这意味着:键本身就是最大的键。请随意查询。

【讨论】:

  • 我的解决方案在所有测试用例中都能正常工作,但仍然不赞成?我还提供了对原始代码的最小修改。
  • 伙计,你是我的英雄!我无法让它工作,天哪。查看您的代码,我想这里的技巧是静态值,对吗?您能否向我解释一下我看不到使它起作用的原因是什么?顺便说一句,您的代码干净、美观且完美!非常感谢但丁!
  • 但丁。另一件事我无法理解。当我递归调用该函数时,static tree* ptr = NULL 行不会重置其值。你能解释一下吗?
  • @PlayHardGoPro 静态变量用于此类目的。静态变量的值只初始化一次,它们的生命周期等于程序的生命周期,不像非静态变量的生命周期不超过函数的执行时间。
  • @PlayHardGoPro 如果你想要一个变量,它应该在一个特定的点初始化自己并且永远不会再初始化,并且还应该记住它以前函数调用的值,记住神奇的静态变量,它们非常有用。
【解决方案2】:

我没有对此进行测试,但我认为它应该可以工作。让我知道它是否错了。 //c++ 11

 #include<iostream>
 using namespace std;
 struct BSTNode{
     int val;
     BSTNode* left;
     BSTNode* right;
 };


 int FindJustLarger(BSTNode*& node, int token, int sofarlarge){
    // for invalid inputs it will return intial value of sofarlarge
    // By invalid input I mean token > largest value in BST
    if(node == nullptr)
        return sofarlarge;

    else if(node->val > token){
        sofarlarge = node->val;
        return FindJustLarger(node->left, token, sofarlarge);}

    else
        return FindJustLarger(node->right, token, sofarlarge);}

int main(){
    BSTNode* head = new BSTNode{5, nullptr, nullptr};
    FindJustLarger(head, 5, NULL);
    delete head;
    return 0;}

【讨论】:

    【解决方案3】:

    您可以在代码中进行一些更改:

    • 您必须从递归调用中返回值

    • 如果未找到该值,则返回NULL。这意味着如果 t-&gt;right == NULL 在最后一个 if 上,则返回 NULL

    • 往左边走时,如果那里没有找到值,答案肯定是节点本身。对于N,它是我们左转的最后一个节点:O。如果是P,答案就是T 本身。

    完成所有这些更改后,代码应如下所示:

    tree *find_first_bigger(tree *t, int x){
       if(t == NULL)
          return NULL;
    
       if(t->value > x) {
          tree *answer = find_first_bigger(t->left, x);
          if (answer != NULL) 
              return answer;
          return t;
       } else if(t->value < x) {
          return find_first_bigger(t->right, x);
       } else if(t->value == x) {
          if (t->right != NULL)
              return tree_first_bigger(t->right);
          return NULL;
       }
    }  
    

    你可以找到我用来测试in this gist的整个代码。

    【讨论】:

      【解决方案4】:

      在您的问题中,您似乎表示要找出给定值“x”的 InOrderSuccessor()。

      如果树中不一定存在“x”,我们需要更改算法。鉴于您提供的示例和问题陈述,这里是在 BST 中查找下一个元素的代码。

      关键案例有:

      • 不存在更大的元素,因为“x”是最大的。
      • 'x' 有一个正确的孩子?
      • YES:获取 x 的右子树的最左子节点。
      • 否:返回父级。

      关键观察是我们不会更新父指针,无论何时我们在树中向右走。

        tree *ptr = root;
        tree *prnt = NULL;
        while (ptr != NULL) {
            if (x == ptr->key) {
                if (ptr->right != NULL) {
                    return GetLeftMostChild(ptr->right);
                } else {
                    return prnt;
                }
            } else if (x > ptr->key) {
                ptr = ptr->right;
            } else {
                prnt = ptr;
                ptr = ptr->left;
            }
        }
      

      这里是leftMostChild()的定义

      tree *GetLeftMostChild(tree *n) {
          tree *ptr = n;
          while (ptr->left != NULL) {
              ptr = ptr->left;
          }
          return ptr;
      }
      

      【讨论】:

      • 我相信您可以简单地将整个 if (prnt != NULL) 块替换为 return prnt注意: OP 已请求返回指针而不是下一个 int 本身)。 if (prnt != NULL) 的检查不是必需的,因为要么有一个指针值,要么你将 return NULL 基于你对 tree *prnt = NULL; 的初始化(如果你 break 会发生这种情况,因为函数的返回是 @ 987654330@)
      • 这更有意义。唯一的另一个 nit 是 return GetLeftMostChild(ptr-&gt;right)-&gt;key; 应该是 return GetLeftMostChild(ptr-&gt;right); 以便返回节点而不是值。您不想返回值的原因是在事件if (x == ptr-&gt;key)if (ptr-&gt;right == NULL) 中,当您break 并尝试return prnt-&gt;key; 时出现段错误(这是试图取消引用NULL 指针)
      猜你喜欢
      • 2011-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多