Ответ 1
Это пересмотренный ответ.
Разновидности классов фанки - они эффективно вставляют класс в середину существующей иерархии, так что теперь вещи, расширяющие list
, теперь расширяются listOrNULL
.
Вместо этого я бы создал небольшую иерархию классов, которая представляет собой "Дерево", которое может быть "Пусто" или "Внутреннее". Класс "Внутренний" будет иметь слот для хранения данных (типа "ЛЮБОЙ" ) плюс левые и правые ссылки, которые будут элементами "Дерево".
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, и поскольку изменение дерева (например, добавление node) копирует все узлы в пути к новому node. A другой подход представляет дерево как matrix
слева, справа, значение трижды. Реализация S4 по-прежнему будет иметь низкую производительность, поскольку обновления экземпляра создадут новые экземпляры, дублируя все. Таким образом, я попал бы в ссылочный класс с полях "значение" (вектор любого дерева, который должен удерживать, и matrix
левого и правого отношений.