我正在尝试在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
存储在由输入节点的id
索引的数组中,可以支持另一个方向的映射。
这当然只是一种可能的实现。可能有多种变化,包括
list
或queue
接口后面提取子链表,而不是存储三个原始指针struct algo_node
中编码父/子/同级关系让我们从输入树的以下定义开始:
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
...但是我真的可以就其中哪些(如果有的话)值得追求的问题做一些指导。
任何帮助将不胜感激!
答案 0 :(得分:0)
您可以使用Int
id标记树节点,并用拉链四处走动(使用Data.Tree
和Data.Tree.Zipper
是个好主意,因为无需重新发明轮子。)然后,您可以使用Data.IntMap
将辅助属性附加到节点,以将节点ID映射到所需的任何内容。特别是,您可以创建一个IntMap
来从该节点的节点ID映射到TreePos Full Int
,以便您可以探索该节点的父级,同级和子级。