测试二叉树是否为搜索树并计算完整分支的算法


10

我需要创建一个递归算法,以查看二叉树是否为二叉搜索树,并用假定的全局计数变量计算有多少个完整分支(一个有左右两个子节点的父节点)。这是我的数据结构类的作业。

到目前为止,我有

void BST(tree T) {
   if (T == null) return
   if ( T.left and T.right) {
      if (T.left.data < T.data or T.right.data > T.data) {
        count = count + 1
        BST(T.left)
        BST(T.right)
      }
   }
}

但是我真的无法弄清楚这一点。我知道该算法无法解决问题,因为如果第二个if语句不正确,则计数将为零。

有人可以帮我解决这个问题吗?


<在节点上如何定义比较运算符?
2012年

即使不是二进制搜索树,您是否要计算计数?
2012年

1
您的算法是否应该返回任何内容,例如truefalse

2
也许您应该首先尝试定义两个单独的函数:一个用于检查它是否是BST,另一个用于计数完整的分支。那应该更易于管理。
sepp2k 2012年

1
@OghmaOsiris我想他说的是因为问题基本上是“这是我的代码,我该如何使其工作?”。如果代码不是伪的,那肯定是一个SO问题。
sepp2k 2012年

Answers:


10

正如其他人已经在注释中指出的那样,您这里确实有两个不相关的功能:测试树是否是搜索树,以及计算完整的分支。除非分配明确要求,否则我将编写两个单独的函数。

让我们看看首先计算完整的分支。这意味着计算同时具有左子节点和右子节点的节点。然后,count = count + 1T.leftT.right都为非空值时,您需要增加计数器()(不T.left.dataT.right.data:此任务的数据无关紧要)。

if (T.left and T.right) {
    count = count + 1

此外,即使右子树为空,也需要浏览左子树,即使左子树为空,也需要浏览右子树。因此,请注意将递归调用放在何处。

要测试该树是否为搜索树,您需要检查数据值。您已经有了一些接近正确比较的东西;不太正确。编写一些具有各种形状(不是很大,有2到5个节点)的示例树,然后对它们运行算法以查看会发生什么。

您仍然需要找到放置有效性检查结果的地方。再次注意观察递归调用的位置(如果仅执行此部分,则有几种解决方案,但是在此阶段,如果只看到一个,就不必担心)。

最后,一旦设法分别编写了两个函数,并在几个示例上对其进行了测试,请仔细地将它们组合在一起(如果作业要求)。


谢谢,我重新阅读了问题,它应该是单独的方法。
OghmaOsiris'3

7

在这样的事情中,倒想通常更容易,所以首先考虑一下您的需求。根据您的描述,让我们列出它们:

  • 递归
  • 有效期
  • 完整节点数

好的,这是一个很短的列表,应该可以管理。让我们从一个空方法开始,我将添加对应该发生的情况的描述。

valid_bst () {
}

现在有效。您如何检查有效性?在聊天中,您说一棵树是有效的“如果...所有左子项均小于父项,而右子项均大于父项。” 我相信您也打算允许平等。那会是t.left.value <= t.value <= t.right.value

valid_bst () {
    This node is valid if t.left.value <= t.value <= t.right.value
}

但是,如果其中一个孩子失踪了怎么办?根据您所说的,我相信您知道如果一个节点丢失(或两个都丢失),该节点仍然有效。让我们添加一下,稍作重组:

valid_bst () {
    This node is valid to the left if 
        there is no left child or 
        it is no greater than the current node.
    This node is valid to the right if 
        there is no right child or 
        it is no less than the current node.
    This node is valid overall if it is valid to the left and right.
}

好的,我们现在知道该节点是否有效。我们如何检查整个树是否有效?它不在数组中,因此我们可能无法/不想线性地对其进行循环。您的作业给出了答案:递归。但是,我们如何使用递归来累积答案呢?我们可以访问三个信息,该节点是否有效,以及询问左节点和右节点是否有效的调用结果。显然,只有当这三个都为真时,树才有效。

valid_bst () {
    This node is valid to the left if 
        there is no left child or 
        it is no greater than the current node.
    This node is valid to the right if 
        there is no right child or 
        it is no less than the current node.
    This node is valid overall if it is valid to the left and right.
    Is the left child valid?
    Is the right child valid?
    This tree is only valid if this node and both its children are.
}

如果您关注的话,它甚至可以告诉我们函数需要返回什么。

现在,我们如何整合计数?您说什么很重要(“一个具有左右两个子节点的父节点”),这应该不难转换为实际代码。检查是否满足该条件,并适当增加计数器。只要记住,这必须在每次正确的地方都可以实现。

当然,我省略了一些细节,例如递归停止条件并检查是否为null。


6

我在上面的三个注释是有关代码问题的三个提示。

  1. 除非您已经特别定义了比较运算符应如何处理节点数据类型,否则直接比较两个节点很可能不会做您想要的事情。您可能的意思是比较存储在节点中的字段,例如node1.value < node2.value
  2. 现在,只有第三个if为true时,才增加计数,确定要这样做吗?顺便说一句,您可能需要仔细检查if语句是否满足您的要求。
  3. 我假设如果树是有效的BST,则想返回true,否则返回false。这意味着在基本情况下,您必须始终返回true或false,并且还应该返回递归调用的结果。

关于第一点:这是伪代码,对吗?因此,只要意图传达给读者,就没有理由定义这样的东西。
sepp2k 2012年

@ sepp2k是真的,我的评论对于伪代码可能有点挑剔。我想我的意思是,我们需要了解比较两个节点的含义。您的观点是,我们已经应该隐含地理解这一点。
2012年

是的,完全正确。
sepp2k 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.