使用Swift枚举实现二叉树
我正在用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,
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
}