我正在尝试学习/理解一些基本算法,今天我决定在Go中编写一个二叉树。这就是结构的样子:
type Node struct {
Value int
Left *Node
Right *Node
}
这是检查树是否包含int的函数:
func (tree *Node) Contains(val int) bool {
if val == tree.Value {
return true
} else if val > tree.Value {
if tree.Right != nil {
return tree.Right.Contains(val)
} else {
return false
}
} else if val < tree.Value {
if tree.Left != nil {
return tree.Left.Contains(val)
} else {
return false
}
} else { // huh
return false
}
}
我编写了一个测试函数来测试树上不同操作的时间。我的Insert()
函数 34ms 需要插入100,000个随机整数,我的Contains()
函数 33ms 检查树是否包含100,000个随机整数。如果我将随机整数的数量增加到1,000,000,则需要运行Insert()
函数 34ms ,但我的Contains()
函数突然需要 321ms 跑。
为什么Contains()
的运行时间会急剧增加,而Insert()
几乎保持不变?
答案 0 :(得分:1)
Insert
函数应该定期重新平衡树,因为不平衡的树可能会导致非常不均匀的遍历时间。因此,Insert
通常要比Contains
慢。
如果你的Insert
函数没有重新平衡树,那么任何给定函数所需的时间都会变成O(n)最坏情况而不是O(log n)并且相当不可预测。
此外,在谈论O(...)时间复杂度时,我们通常会谈论最坏情况行为。如果你对单个调用进行计时,那么任何给定的调用可能比最坏的情况花费更少的时间 - 例如,Contains
查找恰好是root的节点将立即返回,无论大小如何。< / p>