【问题标题】:Construct a tree from a list of data从数据列表构造一棵树
【发布时间】:2021-05-23 17:25:00
【问题描述】:

假设我有一个如下所示的数字列表,

a = [1,23,5,72,3,5,15,7,78,1,5,77,23]

现在我需要根据这些数据构建一棵树。

  1. 根据自定义函数par将数据集分为两部分。我们称这两个部分为 a0、a1。
  2. 对a0、a1分别应用par函数,得到a00、a01、a11、a12。
  3. 重复这个过程,直到末端节点只剩下一个数字。
  4. 对于每个末端节点,我们都有一个“二进制代码”,例如“0010100”,其中 0 代表左侧,1 代表每个特定步骤的右侧。

我试图使用下面的树类,但我一开始就卡住了。

class Node(input):
    def __init__(self, data):
        self.data = data
        self.left = '*'
        self.right = '*'

【问题讨论】:

  • 您专注于如何存储它。想想如何进行分区。
  • 这棵树的根是什么?

标签: python python-3.x tree hierarchical-clustering


【解决方案1】:
class Node(input):
    def __init__(self, data, path='0'):
        self.path = path # 0 means left, 1 means right
        if len(data) = 1:
            self.value = data[0] # this assumes the leaf is a list with single data, rather than the data itself
        else:
            left, right = par(data)
            left = Node(left, side+'0')
            right = Node(right, side+'1')

Node.path 为您提供二进制代码。

【讨论】:

    【解决方案2】:

    不清楚 internal 节点会有哪些值。这可能并不重要,但您可以始终在属于该特定子树的数据数组中分配 first 值。

    “二进制代码”就像从根到节点的导航路径。因此,对于您提供的数据,我们预计会出现这样的树:

    value:                                   1
    path:                       ____________ "" ________ 
                               /                        \
    value:                    1                         15
    path:                  __ 0 __                 _____ 1 _______
                          /       \               /               \
    value:              1         72             15                1
    path:               00        01             10             __ 11 __
                       /  \      /  \           /  \           /        \
    value:            1   23    72   3         15   7         1          77
    path:            000  001   010  011      100  101       110         111
                         /  \       /  \          /  \       /  \       /   \
    value:              23   5     3    5        7    78    1    5     77   23
    path:              0010 0011  0110 0111    1010  1011  1100 1101  1110 1111
    

    您可以使用一个简单的Node 类,它可以存储一个值和一个路径:

    class Node:
        def __init__(self, value, path, left=None, right=None):
            self.value = value
            self.path = path
            self.left = left
            self.right = right
    

    par 函数会做这样的事情:

    def par(data):
        i = len(data) // 2
        return (data[:i], data[i:]) if i else ()
    

    if..else 运算符用于在只有一个数据元素时返回一个空列表。这将在 main 函数中很有用:

    def maketree(data, path=""):
        return Node(data[0], path, *(
            maketree(part, path + str(i)) for i, part in enumerate(par(data))
        ))
    

    这会枚举par 返回的部分并将这些部分传递给递归调用(如果返回任何部分)。同时,递归调用得到一个路径字符串,该字符串以 0 或 1 扩展(即枚举的索引)。

    调用示例:

    a = [1,23,5,72,3,5,15,7,78,1,5,77,23]
    root = maketree(a)
    
    # Output the properties of one particular node:
    node = root.left.left.right.left
    print("value: {}, path: {}".format(node.value, node.path))
    # Outputs: "value: 23, path: 0010"
    

    【讨论】:

    • 非常有用的解决方案。顺便说一句,我需要为递归函数制作一个记忆包装器吗? @trincot
    • Memoization 在这里没有用:只有当一个节点有可能被第二次访问时才有用,并且需要为其计算相同的信息。但这里不是这样。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-06
    • 1970-01-01
    • 1970-01-01
    • 2018-10-24
    • 1970-01-01
    • 2017-08-10
    相关资源
    最近更新 更多