我正在使用Swift枚举进行一些实验,以便更熟悉它们并实现了一个基本的二叉树。它最多可以添加三个项目,但除此之外还可以添加更多项目,但我无法理解为什么它不起作用。
以下是代码:
protocol TreeProtocol {
mutating func insert(value: Int)
func walk()
}
enum Tree:TreeProtocol {
case Empty
case Leaf(Int)
case Node(Int, TreeProtocol?, TreeProtocol?)
init(){
self = .Empty;
}
init(value: Int) {
self = .Leaf(value)
}
init(value: Int, left:TreeProtocol?, right:TreeProtocol?){
self = .Node(value, left, right);
}
mutating func insert(value: Int) {
switch self {
case .Empty:
self = .Leaf(value)
case .Leaf(let currentNodeValue):
let newTree = Tree(value: value) // var here generates a warning
if value < currentNodeValue {
self = .Node(currentNodeValue, newTree, .None)
}
else {
self = .Node(currentNodeValue, .None, newTree)
}
case let .Node(currentNodeValue, leftNode, rightNode):
if (value < currentNodeValue) {
if leftNode == nil {
let newTree = Tree(value: value)
self = .Node(currentNodeValue, newTree, rightNode)
}
else {
var l = leftNode! // unable to call leftNode!.insert() directly
l.insert(value)
}
}
else {
if rightNode == nil {
let newTree = Tree(value: value)
self = .Node(currentNodeValue, leftNode, newTree)
}
else {
var r = rightNode!
r.insert(value)
}
}
}
}
func walk() {
switch self {
case .Empty:
print("Empty")
case .Leaf (let value):
print("\(value), ")
case .Node(let value, let leftNode, let rightNode):
if leftNode != nil {
leftNode!.walk()
}
print("\(value) ")
if (rightNode != nil) {
rightNode!.walk()
}
}
}
}
如果我运行以下测试:
var tree = Tree();
tree.walk()
tree.insert(100)
tree.walk()
tree.insert(50)
tree.walk()
tree.insert(150)
tree.walk()
tree.insert(25)
tree.walk()
输出结果为:
Empty
100
50,
100
50,
100,
150
50,
100,
150
25值未添加到树
(这段代码有点不雅,它只是第一次迭代,其中有几个丑陋的部分可以改进和美化。等待递归的枚举功能被添加到Xcode beta中。)
答案 0 :(得分:7)
因为您正在改变内部节点,而实际上是在创建它们的副本。该副本永远不会插入到树中,只是在修改后才被丢弃。如果在插入l
和r
后重新插入这些节点(分别使用self = .Node(currentNodeValue, l, rightNode)
和self = .Node(currentNodeValue, leftNode, r)
),那么整个树将会更新。这是一个按价值/按参考的问题。
答案 1 :(得分:5)
我知道你已经有了答案,但我真的很喜欢你的实现,并且认为我提供了实现@ Wain解决方案的代码,并简化了一些嵌套的if-else
逻辑。
它涉及对协议的轻微修改,以便insert
返回一个值:
protocol TreeProtocol {
mutating func insert(value: Int) -> TreeProtocol
func walk()
}
然后可以像这样重写insert
函数:
mutating func insert(value: Int) -> TreeProtocol {
switch self {
case .Empty:
self = .Leaf(value)
case .Leaf(let currentNodeValue):
let newTree = Tree(value: value)
self = value < currentNodeValue
? .Node(currentNodeValue, newTree, .None)
: .Node(currentNodeValue, .None, newTree)
case var .Node(currentNodeValue, leftNode, rightNode):
self = value < currentNodeValue
? .Node(currentNodeValue, leftNode?.insert(value) ?? Tree(value: value), rightNode)
: .Node(currentNodeValue, leftNode, rightNode?.insert(value) ?? Tree(value: value))
}
return self
}