Tree construction from a node string
题目
We suppose that the nodes of a multiway tree contain single characters. In the depth-first order sequence of its nodes, a special character ^ has been inserted whenever, during the tree traversal, the move is a backtrack to the previous level.
By this rule, the tree in the figure opposite is represented as: afg^^c^bd^e^^^
Define the syntax of the string and write a predicate tree(String,Tree) to construct the Tree when the String is given. Work with atoms (instead of strings). Make your predicate work in both directions.
解题思路
先用BNF定义字符串语法:
<tree> ::= <letter> <forest> '^'
<forest> ::= | <tree> <forest>
这个题目包含两部份:
- 将多路树转换成字符中
- 将字符中转换成多路树
将多路树转换成字符串
用单元测试描述为:
多路树是一个递归结构,所以我们自然而然地想到用递归方法解决。
假设当给定的多路树只有一个节点,比如(a,[])
,如何构造字符串呢?
先输出根节点,再发现子树列为空即已到达子树列表末尾,则输出^
。
假设给定的多路树再复雑一点,拥有两层结构,根节点拥有两棵树子树,比如(a,[(b,[]),(c,[])])
,如何构造字符串呢?
先轮出根节点,再将子树逐一转换为字符串,最后再输出^
。
归纳起来,将多路树转换为字符串的方法为:
- 先输出根节点
- 再将子树逐转换为字符串,因为每棵子树都是三多路树,所以这𥚃套用步骤1至3到每一棵子树上
- 输出'^'
举一个复雑一点的例子,给定如下三路树:
- 先输出根节点
a
,再逐一转换三棵子树- 转换子树
(f,[(g,[])])
- 先输出节点
f
,再逐一转换唯一的子树- 转换子树
(g,[])
- 先轮出节点值
g
- 子树列为空,即到达子树列表末尾,输出'^'
- 先轮出节点值
- 转换子树
- 到达子树列表末尾,输出'^'
- 先输出节点
- 转换第二棵子树`(c,[])
- 先输出节点值
c
- 子树列表为空,即到达子树列表末尾,输出'^'
- 先输出节点值
- 转换第三棵子树
(b,[(d,[]),(e,[])])
- 先输出节点值
b
,再逐一转换子树- 转换子树
(d,[])
- 先输出节点值
d
- 子树列表为空,即到达子树列表末尾,输出'^'
- 先输出节点值
- 转换子树
(e,[])
- 先输出节点值
e
- 子树列表为空 即到达子树列表末尾,输出'^'
- 先输出节点值
- 转换子树
- 到达子树列表末尾,输出'^'
- 先输出节点值
- 转换子树
- 到达子树列表末尾,输出'^'
代码实现:
reduce
是Python标准库提供的一个函数式的工具,其声明为:
reduce(function, iterable, initializer)
其功能是将function
累积地、从左往右作用于iterable
中的每一个元素。
reduce相当于如下代码:
def reduce(function, iterable, initializer=None):
it = iter(iterable)
if initializer is None:
value = next(it)
else:
value = initializer
for element in it:
value = function(value, element)
return value
这𥚃我们使用reduce将列表中的所有字符串拼接起来。
将字符串转换为多路树
用单元测试描述为:
一样用递归方法解决。一个字符串是由一个节点字符(第一个字符)、表示零至多个子树的字符串和'^'组。将字符串转换为多路树的方法:
- 先取出第一字符作为节点值
- 从剩余子符串中解析出零至多个子树。所有子树都是多路树,所以这𥚃套用步骤1至3解析每一棵子树
- 直至遇到字符'^',一棵完整的多路树解析完毕
举个例子,给定字符串afg^^c^bd^e^^^
。
- 取出第一个字符
a
做为节点值,剩余fg^^c^bd^e^^^
- 从剩余字符串
fg^^c^bd^e^^^
中解柝出零至多个多路树- 解柝第一棵子树
- 取出第一个字符
f
做为节点值,剩余字符串g^^c^bd^e^^^
- 从剩余字符串中解柝出零至多个多路树
- 解柝第一棵子树
- 取出第一个字符
g
做为节点值 - 从剩余字符串
^^c^bd^e^^^
中取出第一个符为^
,已解柝出一棵多路树(g,[])
- 取出第一个字符
- 解柝第一棵子树
- 从剩余字符串
^c^bd^e^^^
中取出第一个字符为^
,表明已解柝出一棵多路树(f,[(g,[])])
- 取出第一个字符
- 解柝第二棵子树
- 从剩余字符中
c^bd^e^^^
中取出第一个字符c
做为节点值,剩余^bd^e^^^
- 从剩余字符串
^bd^e^^^
中取出第一个字符为^
,表明已解柝出一棵多路树(c,[])
- 从剩余字符中
- 解柝第三棵子树
- 从剩余字符串
bd^e^^^
中取出第一个字符b
做为节点值,剩余d^e^^^
- 从剩余字符串中解柝出零至多个多路树
- 解析第一棵子树
- 从剩余字符串
d^e^^^
中取出第一个字符d
做为节点值 - 从剩余字符串中取出第一个字稔为
^
,表明已解柝出一棵多路树(d,[])
- 从剩余字符串
- 解柝第二棵子树
- 从剩余字符串
e^^^
中取出第一个字符e
做为节点值 - 从剩余字符串
^^^
中取出第一个字符^
,表明已解柝出一棵多路树(e,[])
- 从剩余字符串
- 解析第一棵子树
- 从剩余字符串
^^
中取出第一个字符^
,表明已解柝出一棵多路树(b,[(d,[]),(e,[])])
- 从剩余字符串
- 解柝第一棵子树
- 从剩余字符串
^
中取出第一个字符为^
,表明已解柝出一棵多路树(a,[(f,[(g,[])]),(c,[]),(b,[(d,[]),(e,[])])])
代码实现:
字符串多路树多向转换
代码实现:
使用Python内建函数type(v)
检测输入值类型。当输入值类型为元组「tuple」即多路树时,调用tree_to_string(t)
。否则,调用string_to_tree(s)
。