我有一棵树,其格式如下:
节点是树中节点的列表,其高度从顶部开始。高度为0的节点是节点的第一个元素。高度为1的节点(从左到右读取)是节点的下一个元素,依此类推。
n_children是一个整数列表,这样n_children [i] =节点的子节点[i]
例如,给定像{1:{2,3:{4,5,2}}}这样的树,节点= [1,2,3,4,5,2],n_children = [2,0, 3,0,0,0]。
给定一个树,是否可以通过仅遍历树一次生成节点和n_children以及节点中每个节点对应的叶数?
这种表现形式是独一无二的吗?或者两个不同的树可能具有相同的表示形式吗?
答案 0 :(得分:2)
我假设一个特定的树"我们指的是以节点对象的形式给出的树,每个树都保存其值以及对其子节点对象的引用列表。
我提出这个算法:
node=root
开始。node.children
为空,则返回{values_list:[[node.value]], children_list:[[0]]}
否则:
3.1。构建两个列表。一个将被称为values_list
,每个元素都应该是一个值列表。另一个将被称为children_list
,每个元素都应该是一个整数列表。这两个列表中的每个元素将表示以node
开头的子树中的级别,包括node
本身(将在步骤3.3中添加)。
因此values_list[1]
将成为node
子节点的值列表,values_list[2]
将成为node
的孙子节点的值列表。 values_list[1][0]
将是node
最左边的子节点的值。 values_list[0]
将是仅包含一个元素的列表values_list[0][0]
,它将是node
的值。
3.2。对于node
的每个子节点(我们通过node.children引用它们):
3.2.1。从(2.)开始,将子节点设置为node
,并将返回的结果(当函数返回时)分配回child_values_list
和child_children_list
。
3.2.2。如果i
中已有列表,则列表中的每个索引values_list[i]
(它们的长度相同) - 将child_values_list[i]
连接到values_list[i]
并连接child_children_list[i]
到children_list[i]
。否则请指定values_list[i]=child_values_list[i]
和children_list[i]=child.children.list[i]
(这将是推送 - 添加到列表的末尾)。
3.3。将node.value
作为新列表的唯一元素,并将该列表添加到values_list
的开头。将node.children.length
作为新列表的唯一元素,并将该列表添加到children_list
的开头。
3.4。返回values_list
和children_list
当上面的values_list
和children_list
返回node=root
时(来自步骤(1)),我们需要做的就是连接列表的元素(因为它们是列表,每个列表都有一个特定级别的树)。连接list-elements后,生成的values_list_concatenated
和children_list_concatenated
将成为想要的代表。
在上面的算法中,我们只通过开始步骤(2)访问节点,并将其设置为node
,我们只对我们访问的节点的每个子节点执行一次。我们从根节点开始,每个节点只有一个父=>每个节点只访问一次。
对于与每个节点关联的叶子数量:(如果我理解正确 - 子树中节点是其根的叶子数量),我们可以添加另一个列表生成并返回:leaves_list
。
在止损案例中(没有孩子到node
- 步骤(2)),我们将返回leaves_list:[[1]]
。在步骤(3.2.2)中,我们将连接列表元素,如其他两个列表'列表元素。在步骤(3.3)中,我们将对第一个列表元素leaves_list[0]
求和,并将该总和作为我们将添加到leaves_list
开头的新列表中的唯一元素。 (类似于leaves_list.add_to_eginning([leaves_list[0].sum()])
)
为了证明唯一性,我们实际上想要表明函数(让我们称之为rep
用于"表示")保留了树空间的独特性。即它是injection。正如您在wiki链接中所看到的那样,只需要表明存在一个函数(让我们称之为tre
为#34;树")给出一个表示给出了一个树返回,并且每个树都有tre(rep(t))=t
。简单来说 - 我们可以创建一个方法来接受表示并从中构建一个树,并且对于每个树,如果我们进行表示并通过该方法传递该表示,我们将得到完全相同的树。
所以,让我们开始吧!
实际上第一个工作 - 创建该方法(函数tre
)已由您完成 - 通过您解释表示形式的方式。但是,让我们明确指出:
values[0]
,n_children[0]
为子节点数(不设子节点)。i=1
和级别索引li=1
和级别元素索引lei=root.children.length
以及下一级元素累加器nle_acc=0
lei>0
:
4.1。 lei
次:
4.1.1。创建一个节点values[i]
作为值,n_children[i]
作为子节点数。
4.1.2。将新节点添加为尚未填充的级别li
中最左边的子节点(从最右边的方向将树遍历到li
级别,并将新节点分配给第一个引用,即尚未分配。我们知道上一级已完成,因此li-1
级别中的每个节点都有一个children.length
属性,我们可以检查并查看每个节点是否填充了他们应该拥有的子节点数)
4.1.3。添加nle_acc+=n_children[i]
4.1.4。增量++i
4.2。赋值lei=nle_acc
(级别元素可以采用累加器为其收集的内容)
4.3。清除nle_acc=0
(下一级元素累加器需要从下一轮开始累积)现在我们需要证明通过第一个算法然后通过第二个算法(这里的这个算法)传递的任意树将完全不同于原来的那个。
由于我并未尝试证明算法的核心性(尽管我应该这样做),但我们假设它们按照我的意图行事。也就是说,第一个按照你的描述写出表示,第二个按照从左到右的顺序创建一个树,从表示中分配一个值和子数,并根据这些来填充子参考。当涉及到下一个级别的数字。
因此,每个节点根据表示(孩子们如何填充)具有适当数量的子节点,并且该数字是从树中写入的(生成表示时)。对于值也是如此,因此它与原始树是相同的树。
证据实际上应该更详细和详细 - 但我想我现在就把它留在那里。如果需要详细说明,我可以将其作为实际证明。