【问题标题】:Build binary search tree using dictionary in Python在 Python 中使用字典构建二叉搜索树
【发布时间】:2020-09-25 23:02:39
【问题描述】:

我正在尝试在 python 中使用 dict 构建 BST(二叉搜索树)。我不明白为什么我的代码没有向 BST 添加节点。我在这里看到了一个类似的帖子: How to implement a binary search tree in Python? 除了声明一个节点类外,它看起来与我的代码相同,但我想知道为什么我的 dict 实现失败(并希望提高我对在 python 中使用递归传递参数的理解)。

keys = [10,9,2,5,3,7,101,18]
start = {'key': keys[-1], 'val': 1, 'left': None, 'right': None}
def binarySearch(root, node):
# compare keys and insert node into right place
    if not root:
        root = node
    elif node['key'] < root['key']:
        binarySearch(root['left'], node)
    else:
        binarySearch(root['right'], node)

# Now let's test our function and build a BST
while keys:
    key = keys.pop()
    node = {'key': key, 'val': 1, 'left': None, 'right': None}
    binarySearch(start, node)
print(start) # unchanged, hence my confusion. Thx for your time!

=============================================

编辑:这是使它工作的代码!

def binarySearch(root, node):
# compare keys and insert node into right place
    if not root:
        root = node
    elif node['key'] < root['key']:
        if not root['left']: root['left'] = node
        else: binarySearch(root['left'], node)
    else:
        if not root['right']: root['right'] = node
        else: binarySearch(root['right'], node)

以下是我认为幕后发生的事情(为什么一个版本能够添加到 BST 而另一个版本不能):

在最初的版本中,我们将到达一个递归调用,其中root 仍然指向BST 中的None,但随后root = node 使root 指向node,它与start 完全没有联系,即 BST 本身。然后局部变量被删除,不做任何更改。

在修改后的版本中,我们将避免这种情况,因为当我们添加节点时,例如root['left'] = node。这里root 仍然指向原始BST,因此我们正在修改原始BST 中的key-val 对,而不是让root 指向完全在BST 之外的东西。

【问题讨论】:

  • root = node 定义了一个名为root 的新局部变量。你是这个意思吗?
  • 链接问题的接受答案处理 left 或 right 为 None 而不是递归。
  • 函数根内部的@ForceBru 是传递给函数的第一个参数,独立于外部的根。我已经编辑了代码以消除任何混乱。
  • @quamrana 他们能够将节点插入到根目录,所以我想我可以对 dict 做同样的事情,但我不确定它为什么会失败..

标签: python recursion parameter-passing binary-search-tree


【解决方案1】:
#Creted by The Misunderstood Genius
def add_root(e,key):
    ''''
     e is node's name
    key is the node's key search
    '''
    bst=dict()
    bst[e]={'key':key,'P':None,'L':None,'R':None}
    return bst
def root(tree):
   for k,v in tree.items():
       if v['P'] == None:
           return k





def insert(tree, node, key):
    tree[node]={'key':key,'P':None,'L':None,'R':None}
    y =None
    x = root(tree)
    node_key = tree[node]['key']
    while x is not None:
        y=x
        node_root=tree['R']['key']
        if node_key < node_root:
            x=tree[x]['L']
        else:
            x=tree[x]['R']
    tree[node]['P']=y
    if y is not None and node_key< tree[y]['key']:
        tree[y]['L']=node
    else:
        tree[y]['R']=node

    return  tree


def print_all(tree):
   for k,v in tree.items():
       print(k,v)
       print()
'''
Give a root node and key search target 
Returns the name of the node with associated key 
Else None
'''
def tree_search(tree,root, target):
    if root ==None:
        print(" key with node associate not found")
        return root
    if tree[root]['key'] == target:
        return  root
    if target < tree[root]['key']:
        return tree_search(tree,tree[root]['L'],target)
    else:
        return  tree_search(tree,tree[root]['R'],target)

def tree_iterative_search(tree,root,target):


    while root is not  None and tree[root]['key']!=target:

        if target < tree[root]['key']:
            root=tree[root]['L']


        else:
            root=tree[root]['R']


    return root

def minimum(tree,root):
    while tree[root]['L'] is not None:
        root=tree[root]['L']
    return tree[root]['key']






bst=add_root('R',20)

bst=insert(bst,'M',10)
bst=insert(bst,'B',8)
bst=insert(bst,'C',24)
bst=insert(bst,'D',22)
bst=insert(bst,'E',25)
bst=insert(bst,'G',25)
print_all(bst)
print(tree_search(bst,'R',25))
x=tree_iterative_search(bst,'R',25)
print(x)
#print(minimum(bst,'R'))

【讨论】:

    【解决方案2】:

    让我们像 Python 解释器一样运行您的代码。

    让我们从第一个电话开始:binarySearch(start, node)

    这里的start 是定义在脚本顶部的dictnode 是另一个dict(奇怪的是具有相同的值)。

    让我们跳入调用,我们发现自己位于:if not root:,其中root 指的是上面的starttruthy 也是如此,所以这个if 失败了。

    接下来我们发现自己位于:elif node['key'] &lt; root['key']:,在这种情况下不是True

    接下来我们传入else:,我们位于:binarySearch(root['right'], node)

    在我们进入第一个递归调用之前,让我们回顾一下调用的参数是什么:来自startroot['right'] 的值是None,而node 仍然是我们想要的dict插入某处。所以,进入递归调用。

    我们再次发现自己位于:if not root:

    然而这次root只是指第一个递归调用的第一个参数,从上面的参数回顾我们可以看出root指的是None

    现在None 被认为是falsy,所以这次if 成功了,我们进入下一行。

    现在我们在root = node

    这是python中的一个赋值。这意味着python将使用变量root停止引用None并引用node当前引用的任何内容,即dict,它是在while循环中创建的。所以root(这只是一个参数,但你现在可以认为是一个局部变量)指的是dict

    现在发生的事情是我们在第一次递归调用的末尾,这个函数结束了。每当一个函数结束时,所有的局部变量都会被销毁。即rootnode 被销毁。这只是这些变量,而不是它们所指的内容。

    现在我们回到第一个调用站点之后,即binarySearch(root['right'], node)之后

    我们可以在这里看到参数:root['right'], node 仍然引用它们之前引用的任何内容。这就是为什么你的start 没有改变以及为什么你的程序现在应该处理leftright 而不是递归的原因。

    【讨论】:

    • 非常感谢您的清晰解释!请问如何修改代码,才能成功将节点插入到函数外的start中?
    • 好吧,正如我之前评论的那样,它在链接问题的接受答案中。
    • 对...我确实让它工作并将其添加到帖子中。但是,如果我在将root['left'] 传递给递归调用时正确理解了您的答案,它仍会将root 分配为指向root['left'] 作为局部变量,以在该递归调用结束时被销毁。所以我们永远无法在第一次递归之外进行更改?
    • 我指的是'现在发生的事情是我们在第一次递归调用的末尾,这个函数结束了。每当一个函数结束时,所有的局部变量都会被销毁。即根和节点被破坏。这只是这些变量,而不是它们所指的内容。'
    • 您的while keys: 循环(应该是for key in keys: btw)不断将新的nodes 输入binarySearch()(应该是binaryInsert() btw)所以在某些时候leftrightstart 将有自己的nodes。然后在下一次调用中,将有一个 else: binarySearch(...) 传递先前添加的 nodes 之一,变成 root 然后有可能修改 node,就像 start 一样.
    猜你喜欢
    • 1970-01-01
    • 2016-11-06
    • 1970-01-01
    • 2013-10-24
    • 2023-03-17
    • 1970-01-01
    • 1970-01-01
    • 2016-07-01
    • 1970-01-01
    相关资源
    最近更新 更多