我正在构建一个简单的树数据结构,它接受一些输入并在树中创建节点,直到输入足够小。这一切都很好(非常简单)。出于遍历的原因,我想在每个节点上包含对父节点的引用(因此我可以将其向后“向上”),或者在root的情况下为nil。我试图或多或少地这样做(当然,这是一个更简单的版本 - 实际的树是八叉树):
class Recursive {
let value: Int
let child: Recursive?
weak var parent: Recursive?
init(value: Int, parent: Recursive? = nil) {
self.value = value
self.parent = parent
if value > 1 {
self.child = Recursive(value: value-1, parent: self) // fails
} else {
self.child = nil
}
}
}
var r: Recursive? = Recursive(5)
while r != nil {
print(r!.value)
r = r!.child
} // should print 5, 4, 3, 2, 1
当然,这实际上并不奏效。看来你不能在init方法中传递“self”作为参数。我想这是因为整个两步初始化的事情。 Swift中最好的(最惯用的和/或最方便的和/或最高效的)方法是什么?我之前大部分时间都写过Python和一些C语言,所以这个Swift对我来说都很新鲜。
我想我可以编写一个初始化树的单独函数,但似乎应该可以从初始化方法中完成所有操作。我只是无法弄清楚如何。
答案 0 :(得分:2)
问题是您只能将self
传递给递归调用
完全初始化后(否则递归调用
函数可以访问未初始化的属性。)
一种可能的解决方案是在之后分配孩子的父母
孩子已经建成。这允许您将child
保持为常量
属性:
class Recursive {
let value: Int
let child: Recursive?
weak var parent: Recursive?
init(value: Int) {
self.value = value
if value > 1 {
self.child = Recursive(value: value - 1)
// Now `self` is fully initialized!
self.child?.parent = self
} else {
self.child = nil
}
}
}
只是为了好玩:"链接列表遍历"可以没有 强行打开:
var r: Recursive? = Recursive(value: 5)
while let node = r {
print(node.value)
r = node.child
}
甚至更短,带常量列表头:
let r = Recursive(value: 5)
for node in sequence(first: r, next: { $0.child }) {
print(node.value)
}
答案 1 :(得分:0)
您的child
参数应该是var
而不是let
,它应该有效。您也可以删除else
,因为child
默认为nil
(默认情况下var
选项为nil
)