使用Swift枚举实现二叉树

使用Swift枚举实现二叉树,swift,Swift,我正在用Swift枚举做一些实验,以便更加熟悉它们,并实现了一个基本的二叉树。当加上三个项目时,它是有效的,但是再加上更多的项目并不能改变它,我也不明白为什么它不起作用 代码如下: protocol TreeProtocol { mutating func insert(value: Int) func walk() } enum Tree:TreeProtocol { case Empty case Leaf(Int) case Node(Int,

我正在用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()
            }
        }
    }
}
输出为:

    Empty

    100

    50,
    100

    50,
    100,
    150

    50,
    100,
    150
未将25值添加到树中


(这段代码有点不雅观,它只是第一次迭代,其中有几个丑陋的部分可以改进和美化。等待递归枚举功能添加到Xcode beta版)。

因为您正在变异内部节点,而这实际上是在创建它们的副本。该副本从未插入到树中,只是在修改后丢弃。如果在插入
l
r
后重新插入这些节点(分别使用
self=.Node(currentNodeValue,l,rightNode)
self=.Node(currentNodeValue,leftNode,r)
,则整个树将得到更新。这是一个按值/按引用的问题。

我知道您已经有了答案,但我真的很喜欢您的实现,我想我会提供实现@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
}
mutating func insert(值:Int)->TreeProtocol{
切换自身{
案例。空:
self=.Leaf(值)
case.Leaf(让currentNodeValue):
设newTree=Tree(值:value)
self=值<当前节点值
?.节点(currentNodeValue、newTree、.None)
:.Node(currentNodeValue、.None、newTree)
案例变量节点(currentNodeValue、leftNode、rightNode):
self=值<当前节点值
?节点(currentNodeValue,leftNode?.insert(值)??树(值:值),rightNode)
:.Node(currentNodeValue、leftNode、rightNode?插入(值)?树(值:值))
}
回归自我
}

不确定您是否可以通过引用进行模式匹配和获取,以便无需插入副本即可进行内联更新…谢谢。你能进一步解释一下你的评论是什么意思吗?我想知道是否有办法使枚举值通过引用可用,无论是在定义中还是在模式匹配中
enum
s始终是值类型。如果对二叉树使用
enum
,则始终使用值类型。谢谢。我知道我的代码不雅观,它只是第一次迭代,你的流线更整洁。我期待着在Xcode支持递归枚举后,不使用协议重新编写它。我之所以花时间是因为我喜欢你这样做,我打算偷它:)一旦递归枚举出现,你可能偷了一些旧式的东西,然后你会因为过时而名声大噪。我是否为你获得声誉积分那个也许是“老式”徽章?干杯
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
}