使用Swift枚举实现二叉树

时间:2015-06-26 15:07:21

标签: swift

我正在使用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中。)

2 个答案:

答案 0 :(得分:7)

因为您正在改变内部节点,而实际上是在创建它们的副本。该副本永远不会插入到树中,只是在修改后才被丢弃。如果在插入lr后重新插入这些节点(分别使用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
}