完全平衡树的经典实现是如下图的一个数组(来自wikipedia http://en.wikipedia.org/wiki/Binary_tree)
这里是从0开始计数的,所以子节点的坐标要相应的调整为2 * x - 1 和2 * x。
为了方便,计数任然从1开始。对于一个节点x,它的子节点是 2 * x和 2 * x + 1;
定义如下的Tree的数据结构:
sealed abstract class Tree[+T] {
def addValue[U >: T <% Ordered[U]](x: U): Tree[U]
}
case class Node[+T](value: T, left: Tree[T], right: Tree[T]) extends Tree[T] {
def addValue[U >: T <% Ordered[U]](x: U): Tree[U] = {
if (x < value) {
Node(value, left.addValue(x), right)
} else if (x > value) {
Node(value, left, right.addValue(x))
} else {
this
}
}
override def toString = "T(" + value.toString + " " + left.toString + " " + right.toString + ")"
}
case object End extends Tree[Nothing] {
def addValue[U <% Ordered[U]](x: U) = Node(x)
override def toString = "."
}
这里不难理解,Tree要么是一个Node,包含左子树和右子树,要么是一个End,类似于C语言里面的Null指针。生成一棵树,可以不断的在已有的树上面调用addValue,添加节点,从而得到一个新的树。这个数据结构是不可变的,每次增加新的节点(这里没有删除的操作),都会得到一个新的tree,而原来的tree是不会改变的。为了能更方便,再为Node增加一个Companion Object。
object Node {
def apply[T](value: T): Node[T] = Node(value, End, End)
}
2. 接下来,实现完全平衡树。完全平衡树,简单说,就是节点从上到下,从左到右依次排列。这里要利用的性质也是一再提起的,对于任何一个节点x, 其左子树是2 * x,右子树是2 * x + 1;而我们要做的就是把这个性质用代码表现出来。
object Tree {
def completeBinaryTree[T](nodes: Int, value: T): Tree[T] = {
def go(x: Int): Tree[T] =
if(2 * x > nodes) Node(value)
else if(2 * x + 1 > nodes) Node(value, go(2 * x), End)
else Node(value, go(2 * x), go(2 * x + 1))
go(1)
}
}
这里使用了递归调用,代码就表现了所要做的事情。这个是我的实现版本,还有一个参考的实现,要更简洁一点。
object Tree {
def completeBinaryTree[T](nodes: Int, value: T): Tree[T] = {
def generateTree(addr: Int): Tree[T] =
if (addr > nodes) End
else Node(value, generateTree(2 * addr), generateTree(2 * addr + 1))
generateTree(1)
}
}
有兴趣的可以参考 http://aperiodic.net/phil/scala/s-99/p63.scala, 这是一个学习scala不错的网站。