Swift

时间:2017-11-21 08:32:37

标签: swift

我正在构建一个简单的树数据结构,它接受一些输入并在树中创建节点,直到输入足够小。这一切都很好(非常简单)。出于遍历的原因,我想在每个节点上包含对父节点的引用(因此我可以将其向后“向上”),或者在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对我来说都很新鲜。

我想我可以编写一个初始化树的单独函数,但似乎应该可以从初始化方法中完成所有操作。我只是无法弄清楚如何。

2 个答案:

答案 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