Python 计算任意(非二叉)树的高度

Python 计算任意(非二叉)树的高度,python,algorithm,data-structures,tree,Python,Algorithm,Data Structures,Tree,我目前正在学习在线数据结构课程,这是家庭作业之一;请引导我找到答案,而不是给我答案 提示如下: 任务。将为您提供一个有根树的描述。您的任务是计算并输出其高度。回想一下,(有根)树的高度是节点的最大深度,或者是从叶子到根的最大距离。您得到的是任意树,不一定是二叉树 输入格式。第一行包含节点数n。第二行包含来自的整数−1至n−1节点的父节点。如果其中的第i个(0≤ 我≤ N−1) 是−1,节点i是根,否则它是第i个节点的父节点的基于0的索引。可以保证只有一个根。可以保证输入代表一棵树 约束条件。1≤

我目前正在学习在线数据结构课程,这是家庭作业之一;请引导我找到答案,而不是给我答案

提示如下:

任务。将为您提供一个有根树的描述。您的任务是计算并输出其高度。回想一下,(有根)树的高度是节点的最大深度,或者是从叶子到根的最大距离。您得到的是任意树,不一定是二叉树

输入格式。第一行包含节点数n。第二行包含来自的整数−1至n−1节点的父节点。如果其中的第i个(0≤ 我≤ N−1) 是−1,节点i是根,否则它是第i个节点的父节点的基于0的索引。可以保证只有一个根。可以保证输入代表一棵树

约束条件。1≤ N≤ 105

我当前的解决方案有效,但当n>102时速度非常慢。这是我的密码:

# python3

import sys
import threading

# In Python, the default limit on recursion depth is rather low,
# so raise it here for this problem. Note that to take advantage
# of bigger stack, we have to launch the computation in a new thread.
sys.setrecursionlimit(10**7)  # max depth of recursion
threading.stack_size(2**27)   # new thread will get stack of such size
threading.Thread(target=main).start()

# returns all indices of item in seq
def listOfDupes(seq, item):
    start = -1
    locs = []
    while True:
        try:
            loc = seq.index(item, start+1)
        except:
            break
        else:
            locs.append(loc)
            start = loc
    return locs

def compute_height(node, parents):
    if node not in parents:
        return 1
    else:
        return 1 + max(compute_height(i, parents) for i in listOfDupes(parents, node))

def main():
    n = int(input())
    parents = list(map(int, input().split()))
    print(compute_height(parents.index(-1), parents))
输入示例:
>>5

>>4-1411

这将产生一个
3
的解,因为根是
1
3
4
的分支,然后是
0
2
的分支,这使得这棵树的高度为
3


如何改进此代码,使其在3秒的时间基准下运行?另外,在另一种语言中这会更容易吗?

这个问题的结构看起来应该是自下而上而不是自上而下地解决。您自上而下的方法花费时间寻找,这是不必要的,例如:

def height(tree):
    for n in tree:
        l = 1
        while n != -1:
            l += 1
            n = tree[n]
        yield l

In []:
tree = '4 -1 4 1 1'
max(height(list(map(int, tree.split()))))

Out[]:
3
或者,如果您不喜欢发电机:

def height(tree):
    d = [1]*len(tree)
    for i, n in enumerate(tree):
        while n != -1:
            d[i] += 1
            n = tree[n]
    return max(d)

In []:
tree = '4 -1 4 1 1'
height(list(map(int, tree.split())))

Out[]:
3

以上是暴力,因为它没有利用重用您已经访问过的树的部分,添加它应该不会太难。

您的算法花费大量时间搜索输入中的数字位置。如果只对输入进行一次迭代,就可以在遇到每个数字时记录它们的位置,这样以后就不必反复搜索。考虑什么样的数据结构对记录这些信息是有效的。只要你正确地使用算法,

< P> Python就可以了。由于您只是寻求指导,请考虑:

1) 我们知道一个节点的深度,如果其父节点的深度已知;及 2) 我们对树的结构不感兴趣,所以我们可以扔掉不相关的信息

根节点指针的值为-1。假设我们将其子节点指向根节点的指针替换为值-2,将其子节点的指针替换为值-3,以此类推。其中最大的绝对值是树的高度

如果我们从任意节点N(0)遍历树,我们可以在节点N(k)处遇到负值时立即停止,此时我们可以将每个节点替换为其父节点的值,小于1。也就是说,N(k-1)=N(k)-1,N(k-2)=N(k-1)-1。。。N(0)=N(1)-1。随着越来越多的指针被其深度所取代,每次遍历都更有可能因遇到深度已知的节点而终止。事实上,该算法基本上需要线性时间


因此:将数据加载到数组中,从第一个元素开始,遍历指针,直到遇到负值。构建另一个遍历的节点数组。遇到负值时,使用第二个数组将第一个数组中的原始值替换为其深度。对第二个元素执行相同的操作,以此类推。记录你所遇到的最大深度:这就是你的答案

生成一个线程没有任何优势,只会增加开销,生成一个线程池来解决问题的不同部分可能会有所帮助,但python有GIL,除非您在执行IO。您有示例输入吗?@AChampion我在我的问题中添加了示例输入。另外,我产生了另一个线程,因为由于一些测试用例的大小,问题建议使用它。在任何情况下,我都不认为这会导致我的计时问题,是吗?您的代码片段包含一个从未定义过的
d
。看起来它可能是您删除的优化或类似的内容所遗留下来的。@user2357112您是对的,对保留在。。。删除。我发现同样的问题张贴在-提交了上面的修剪和它通过:320/320在2.83s。