這是修改後的答案。
階級聯盟很時髦 - 他們有效地插入一個類到現有的層次結構的中間,所以突然擴展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 < [email protected]) {
l <- insert(x, [email protected])
r <- [email protected]
} else {
l <- [email protected]
r <- insert(x, [email protected])
}
Tree([email protected], 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 < [email protected]) member(x, [email protected])
else if ([email protected] < x) member(x, [email protected])
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類創建效率低下以及修改樹(例如,添加節點)將路徑中的所有節點複製到新節點,因此當有大量更新時,這不會很有效。 A different approach將該樹表示爲左值,右值三元組的matrix
。 S4的實現仍然會有糟糕的表現,因爲實例的更新會創建新的實例,複製所有內容。所以我最終會參考一個參考類,其中包含字段'value'(樹的任何一個向量,以及左右關係的一個向量)。
這是錢伯斯在軟件推薦的數據分析(+1) – Henrik
完美的辦法,謝謝 – RockScience
它完美,非常感謝 – eblondel