Algorithm 如何在Haskell中表示两棵树之间的映射?
我正试图在Haskell中实现一个树处理算法(由于这是我的第一个Haskell程序!),我正在努力设计数据结构。有哪位FP大师能帮忙吗 我将从描述算法的重要特征开始,勾勒出我将如何使用命令式语言来实现这一点,并以我在Haskell中迄今为止所做的跌跌撞撞的小步骤结束 问题 我不会详细描述完整的算法,但要点如下:Algorithm 如何在Haskell中表示两棵树之间的映射?,algorithm,haskell,tree,mapping,abstract-syntax-tree,Algorithm,Haskell,Tree,Mapping,Abstract Syntax Tree,我正试图在Haskell中实现一个树处理算法(由于这是我的第一个Haskell程序!),我正在努力设计数据结构。有哪位FP大师能帮忙吗 我将从描述算法的重要特征开始,勾勒出我将如何使用命令式语言来实现这一点,并以我在Haskell中迄今为止所做的跌跌撞撞的小步骤结束 问题 我不会详细描述完整的算法,但要点如下: data AnnotatedTree = Tree Int addIndex :: Int -> AnnotatedTree -> (AnnotatedTree, Int)
data AnnotatedTree = Tree Int
addIndex :: Int -> AnnotatedTree -> (AnnotatedTree, Int)
indexedTree = addIndex 0 tree
- 该算法在两棵玫瑰树X和Y上运行
- 算法的第一阶段根据每个节点及其子节点的标签和属性,计算每个节点的一些派生属性
- 这些派生属性用于计算两棵树之间的部分映射,因此X中的节点可能与Y中的节点关联,反之亦然。由于映射是局部的,因此可以映射X或Y中的任何节点(即,在另一棵树中有一个伙伴),或者可以取消映射
- 算法的最后阶段通过检查映射节点的父节点/子节点/兄弟节点的一系列操作来优化这些映射
- 给定对节点的引用,提供对该节点的父节点、该节点的兄弟节点以及该节点的子节点的访问
- 给定输入树中的节点,允许使用附加信息(派生属性和对另一棵树中节点的可选引用)对该节点进行注释
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;
};
data Tree = Leaf Label Attributes
| Node Label Attributes [Tree]
嵌入在每个节点中的指针显然支持算法所需的上/下/左/右遍历
可以通过定义以下结构来实现注释:
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;
};
算法的第一阶段为每个输入树中的每个节点
构造一个算法节点
从算法节点
到节点
的映射非常简单:遵循嵌入的*节点
指针。通过将algou节点
s存储在一个数组中,由输入节点的id
索引,可以支持另一个方向的映射
当然,这只是一种可能的实现。有许多变化是可能的,包括
- 在
或列表
接口后面抽象子链表,而不是存储三个原始指针队列
- 不要通过索引将输入树与算法树相关联,而是直接在
struct algou_节点中编码父/子/同级关系
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;
};
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
可能树
- 但是,我看不到一种方法可以走到映射节点的父节点/同级节点
任何帮助都将不胜感激 您可以使用
Int
id标记树节点,并使用拉链(使用Data.tree
和Data.tree.Zipper
是个好主意,因为无需重新发明轮子)。然后,可以使用Data.IntMap
将辅助属性附加到节点,以将节点id映射到所需的任何对象。特别是,您可以创建一个IntMap
来从节点id映射到该节点的TreePos Full Int
,以便可以查看该节点的父节点、同级节点和子节点 如果x
中的一个节点x
在y
中有一个对应的节点y
,那么y
中与x
的后代对应的所有节点都是y
的后代吗?@danidiaz否,不一定。我认为拉链确实是您在这里想要的。是否值得将我的数据转换为data.Tree以便我可以使用data.Tree.Zipper?还是我应该自己拉拉链?这两条路线上都有我应该知道的陷阱吗?