这是一个修改后的答案。
类联合很时髦——它们有效地将一个类插入到现有层次结构的中间,所以突然之间,扩展的东西list
现在扩展了listOrNULL
。
相反,我会创建一个小的类层次结构,它表示可以是“空”或“内部”的“树”。“内部”类将有一个槽来包含数据(类型为“ANY”),加上左右链接,这将是“树”元素。
setClass("Tree")
setClass("Empty", contains="Tree")
setClass("Internal", contains="Tree",
representation=representation(elem="ANY", left="Tree", right="Tree"),
prototype=prototype(left=new("Empty"), right=new("Empty")))
我将为我的树编写一个构造函数,其中包含用于创建一棵空树的方法,以及从一个元素加上左右后代的树。
setGeneric("Tree", function(elem, left, right) standardGeneric("Tree"),
signature="elem")
setMethod(Tree, "missing", function(elem, left, right) new("Empty"))
setMethod(Tree, "ANY", function(elem, left, right) {
new("Internal", elem=elem, left=left, right=right)
})
基本操作是将元素x
插入树中t
setGeneric("insert", function(x, t) standardGeneric("insert"))
setMethod(insert, c("ANY", "Empty"), function(x, t) {
Tree(x, Tree(), Tree())
})
setMethod(insert, c("ANY", "Internal"), function(x, t) {
if (x < t@elem) {
l <- insert(x, t@left)
r <- t@right
} else {
l <- t@left
r <- insert(x, t@right)
}
Tree(t@elem, l, r)
})
另一种操作是测试成员资格
setGeneric("member", function(x, t) standardGeneric("member"))
setMethod(member, c("ANY", "Empty"), function(x, t) FALSE)
setMethod(member, c("ANY", "Internal"), function(x, t) {
if (x < t@elem) member(x, t@left)
else if (t@elem < x) member(x, t@right)
else TRUE
})
这个实现的一个有趣的、功能性的属性是它是持久的
> t <- Tree()
> t1 <- insert(10, t)
> t2 <- insert(5, t1)
> t3 <- insert(7, t2)
> t4 <- insert(15, t3)
> which(sapply(1:20, member, t4))
[1] 5 7 10 15
> which(sapply(1:20, member, t2))
[1] 5 10
当有很多更新时,这不会是有效的,因为创建 S4 类的效率低下,并且因为修改树(例如,添加节点)会将路径中的所有节点复制到新节点。另一种方法将树表示matrix
为左、右、三元组。S4 实现的性能仍然很差,因为实例的更新会创建新实例,复制所有内容。所以我最终会进入一个参考类,其中包含“值”字段(树应该包含的任何向量matrix
以及左右关系的向量。