我正在尝试在 Haskell 中实现树处理算法,并且(因为这是我的第一个 Haskell 程序!),我正在努力设计数据结构。那里的任何 FP 大师都可以伸出援手吗?
我将首先描述算法的重要特征,勾勒出我将如何使用命令式语言来解决这个问题,并以到目前为止我在 Haskell 中所做的蹒跚学步的小步骤结束。
问题
我不会详细描述完整的算法,但要点如下:
因此,数据结构必须具有以下特征:
命令式解决方案的草图
如果我要使用命令式语言来实现这个算法,那么解决方案将如下所示。
让我们假设起点是输入树的以下定义:
struct node {
// Identifier for this node, unique within the containing tree
size_t id;
// Label of this node
enum label label;
// Attributes of this node
// An attribute can be assumed to be a key-value pair
// Details of the attributes themselves aren't material to this
// discussion, so the "attribute" type is left opaque
struct attribute **attributes;
size_t n_attributes;
// Pointer to parent of this node
// NULL iff this node is root
struct node *parent;
// Pointer to first child of this node
// NULL iff this node is leaf
struct node *child;
// Double-linked list of siblings of this node
struct node *prev;
struct node *next;
};
嵌入在每个节点中的指针明确支持算法所需的上/下/左/右遍历。
可以通过定义以下结构来实现注解:
struct algo_node {
// Pointer to input node which has been wrapped
struct node *node;
// Derived properties computed by first phase of the algorithm
// Details of the properties themselves aren't material to this
// discussion, so the "derived" type is left opaque
struct derived props;
// Pointer to corresponding node in the other tree
// NULL iff this node is unmatched
struct node *match;
};
算法第一阶段构造一个
algo_node
每个node
在每个输入树中。来自
algo_node
的映射到 node
很简单:遵循嵌入式 *node
指针。可以通过存储 algo_node
支持其他方向的映射s 在一个数组中,由 id
索引输入节点。这当然只是一种可能的实现方式。许多变化是可能的,包括
list
后面的子链表或 queue
接口(interface),而不是存储三个原始指针 struct algo_node
中编码父/子/兄弟关系迁移到 Haskell
让我们从输入树的以下定义开始:
data Tree = Leaf Label Attributes
| Node Label Attributes [Tree]
可以通过以下方式实现每个具有 id 的节点的增强:
data AnnotatedTree = Tree Int
addIndex :: Int -> AnnotatedTree -> (AnnotatedTree, Int)
indexedTree = addIndex 0 tree
类似地,我们可以编写一个计算派生属性的函数:
data AnnotatedTree = Tree DerivedProperties
computeDerived :: DerivedProperties -> AnnotatedTree -> (AnnotatedTree, DerivedProperties)
derivedTree = computeDerived DefaultDerived tree
上面的代码片段可以通过很少的工作进行调整,例如
AnnotatedTree
包含索引和派生属性。但是,我不知道从哪里开始表示两棵树之间的映射。根据一些阅读,我有一些不成熟的想法......
AnnotatedTree
包含从另一棵树的根到映射节点的路径 - 编码为每个连续子列表的索引列表,[Integer]
AnnotatedTree
直接包含对映射节点的引用,如 Maybe Tree
...但我真的可以提供一些指导,说明其中哪些(如果有的话)值得追求。
任何帮助将非常感激!
最佳答案
您可以使用 Int
标记树节点id's,然后用 zipper 在它们周围走动(使用 Data.Tree
和 Data.Tree.Zipper
是个好主意,因为不需要重新发明轮子)。然后,您可以使用 Data.IntMap
将辅助属性附加到节点。将节点 ID 映射到您想要的任何内容。特别是,您可以创建一个 IntMap
从节点 id 映射到 TreePos Full Int
以便您可以探索该节点的父节点、兄弟节点和子节点。
关于algorithm - 如何在 Haskell 中表示两棵树之间的映射?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55680121/