使用python搜索n-ary树的函数

时间:2013-11-26 07:01:17

标签: python search

我正在尝试为n-ary树构建搜索功能。以下是节点类的用法:

class node(object):
  """docstring for node"""
  def __init__(self, val=''):
    self.val = val #value of the node
    self.subtrees = [] #list of subtree node objects

以下是我如何调用搜索功能的代码:

temp_search(root, "1")

并且有一个节点的值为“1”。我希望在成功搜索时返回节点对象。

以下是我实施的第一个搜索功能:

#temp_search v0.1
def temp_search(node, key):
    if node.val == key:
        print 'Found', node
        return node
    for subtree in node.subtrees:         
        return temp_search(subtree, key)

上面的内容返回'None',它从未打印过'Found'

现在我修改了一下:

#temp_search v0.2
def temp_search(node, key):
    if node.val == key:
        print 'found', node
        return node
    for subtree in node.subtrees:         
        temp_search(subtree, key)  

虽然它返回'None'但它仍然打印'Found'。好的,那是一些改进。

所以我意识到即使在返回节点之后,循环也在每个子树对象上运行。这有任何意义吗?因为我认为一旦它返回了某些东西,它应该出来了吗?所以再次修改它:

#temp_search v0.3
def temp_search(node, key):
    if node.val == key:
        print 'Found', node
        return node       
    for subtree in node.subtrees:         
        temp = temp_search(subtree, key)
        if temp:
            return temp

同样我实现了这样的多搜索[即它应该返回其值与key]

匹配的所有节点
#temp_multi_search v0.1
def temp_multi_search(some_node, key, result=[]):
    if some_node.val == key:
        print 'found', some_node
        return result.append(some_node)
    for subtree in some_node.subtrees:         
        temp = temp_multi_search(subtree, key, result)
        if temp:
            result.append(temp)
    return result

我会在上面调用这样的函数:

temp_multi_search(root, "1")

但我的结果是:

[<__main__.node object at 0x101eb4610>, [...], [...], [...], [...], [...], [...], [...], <__main__.node object at 0x101eb47d0>, [...], [...], [...], [...]]

所以它附加了空列表(?)。这就是我修复它的方法:

#temp_multi_search v0.2
def temp_multi_search(some_node, key, result=[]):
    #result = []
    if some_node.val == key:
        print 'found', some_node
        return result.append(some_node)
    for subtree in some_node.subtrees:         
        temp = temp_multi_search(subtree, key, result)
        if isinstance(temp, node):
             result.append(temp)
    return result

现在我会得到正确的预期结果:

[<__main__.node object at 0x10b697610>, <__main__.node object at 0x10b6977d0>]

以下是我的问题:

  1. 为什么temp_search v0.1失败了?当遍历每个子树时,找到搜索结果时,返回该值。为什么循环没有被终止?
  2. 在temp_search v0.2中,我在for循环中没有return语句。那么这里有什么不同呢?由于找到了对象,但如何成功返回?
  3. 我是否以正确的方式实施了temp_search v0.3?有什么改进吗?
  4. 为什么temp_multi_search v0.1失败?
  5. 我是否以正确的方式实施了temp_multi_search v0.2?有什么改进吗?
  6. 以下是我的想法:

    1. 我认为for循环只运行一次。它仅在第一个子树中进行搜索(递归),如果项目不存在则返回它返回none。我通过发送第一个子树中存在的值
    2. 来确认这一点
    3. 这里for循环在每个子树上成功运行,这就是它能够找到节点的原因。但是如何让它返回节点而不是temp_search v0.3的其他方法呢?我发现temp_search v0.3 less pythonic
    4. -
    5. 我认为它失败了,因为返回temp会是一些列表,所以只是将它追加到结果中。
    6. -

1 个答案:

答案 0 :(得分:2)

  1. 你的答案是对的。由于第一个子树上的函数调用总是返回(无论是否找到值),它都不会检查下一个子树。
  2. 你没有return语句,所以在函数结束时Python会隐式插入return None
  3. 这已经是最佳选择了。没有单一的Python语句可以做到这一点。
  4. 添加了列表(非空列表!),因为您执行return result,因此父函数调用将接收结果列表(结果)。然后它将附加到result的本地副本,然后返回。
  5. 您可以通过不将result作为参数来改善这一点:
  6. #temp_multi_search v0.25
    def temp_multi_search(some_node, key):
        result = []                    # Line 1
        if some_node.val == key:
            print 'found', some_node
            result.append(some_node)   # Line 2
        for subtree in some_node.subtrees:         
            result.extend(temp_multi_search(subtree, key)) # Line 3
        return result
    

    说明:

    它将首先检查根节点上的值,如果它不匹配,我们不会将该节点附加到搜索结果,否则,我们将其添加到我们的结果中(这只包含它自己) 。接下来我们检查每个子树。

    现在,我们已经知道函数temp_multi_search(subtree, key)将在该树上返回所有出现次数。因此,在我们对每个孩子调用temp_multi_search(subtree, key)之后,我们在该子树中找到的结果扩展到我们到目前为止的结果中(可能包含了之前孩子的结果)。

    在迭代所有孩子的最后,我们返回结果。

    示例:

    假设我们在下面的树中查找数字1,并期望该函数返回所有出现的内容。

              0
       _______|________
       |      |       |
       1      2       3
      _|_    _|_   ___|___
      | |    | |   |  |  |
      1 4    1 5   6  1  7
    

    首先我们打电话给temp_multi_search(root,1)。它不是1,所以result现在仍然是空的。

    接下来我们检查每个子树:

    1. 子级1:节点值匹配,因此我们将其添加到结果中(在第2行)。现在说我们有result = [node1]。然后检查每个子树:
      • GrandChild 1:节点值匹配,因此我们将其添加到结果中(在第2行)。没有更多的子树。返回[node2]。 Child 1调用会将结果[node2]扩展到结果[node1](第3行)。所以Child 1现在有[node1, node2]
      • GrandChild 2:节点值不匹配。没有更多的子树。返回[]。子1扩展空列表,所以没有变化。
    2. 孩子2:不匹配。检查每个子树:
      • GrandChild 3:比赛。添加到结果(第2行)。没有更多的子树。返回[node5]。儿童2成为[node5](第3行)。
      • GrandChild 4:不匹配。没有更多的子树。返回[]。孩子2仍然是[node5]
    3. 孩子3:不匹配。检查每个子树:
      • GrandChild 5:不匹配。没有更多的子树。返回[]
      • GrandChild 6:匹配添加到结果(第2行)。返回[node9]。子3将其扩展为[node9](第3行)
      • GrandChild 7:不匹配。没有更多的子树。返回[]。
    4. 在每个提到的步骤结束时,返回的结果将通过第3行扩展到Root结果。因此,在步骤1之后,根结果为[node1, node2]。在第2步之后,根结果为[node1, node2, node5]。在第3步之后,根结果为[node1, node2, node5, node9]

      然后在检查所有孩子后,返回结果。