これは修正された回答です。
クラス ユニオンはファンキーです。クラスを既存の階層の中間に効果的に挿入するため、拡張するものが突然list
拡張しlistOrNULL
ます。
代わりに、「空」または「内部」のいずれかになる「ツリー」を表す小さなクラス階層を作成します。"Internal" クラスには、データ ("ANY" 型) を格納するためのスロットと、"Tree" 要素となる左右のリンクがあります。
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
と左右の関係のベクトル)を持つ参照クラスになります。