日常开始前胡扯一通
如我上一篇文章所说,先拣软柿子捏,找一些熟悉的东西试试手,权当复习。
当我思考究竟该怎么写这第一篇时,突然意识到Treap可能是一个没什么用的东西,尤其是在实际的工程开发中。在竞赛中,Treap可能是一个好的选择,因为它写起来快,易调试,相比那些复杂的平衡树来说效率并没有太多的下降。然而在实际开发中,要么直接会去使用标准模板库里的map、set这样的现成平衡树,要么索性做的精致一点,直接写一个AVL或者RBTree封装好。Treap就处在了一个比较尴尬的位置。
当然无论如何,这并不影响本文的内容。
特别提醒:本人现在LaTeX基本不会用,目测本文要出现大量的图片……
从二叉查找树说起
为了凑点字数,还是从普通的二叉查找树说起吧。
一个简单的问题
一个长度为n的有序序列,从中查找一个指定的值,要花多少时间?
一个最简单的做法就是一个个去试。如果你运气好,第一个就碰上了;如果你运气不好,最后一个才是你要查的值,那就需要把n个值都检查一遍。时间复杂度O(n)。
当然你可能注意到了有序这个有用的性质,所以可以采用二分查找的方式,具体就不赘述了。时间复杂度O(log(n))。
但是如果要添加一个数据怎么办?要保证序列的有序性,你必须要插入到适当的位置。这个位置同样可以通过二分查找在O(log(n))的时间中找出。
可是插入的过程呢?我们必须把后面的数据一个个顺次往后挪一格,而这需要O(n)的时间。
太慢了!我们需要快一点的方法。
二叉查找树
这种时候,一个可能的解决方法就是使用二叉查找树。
那个说树状数组的给我出来,我保证不打死你
二叉查找树是这样的一种数据结构,保证在任意一个节点上,左儿子的值小于自己的值小于右儿子的值(这里暂且不考虑等于的情况),从而满足中序遍历的结果是有序的。
如图所示:
原谅我弄出这么个lowB的图(掩面)
这一棵二叉查找树的中序遍历就是2-5-8-13-17-20-22-26。
使用二叉查找树有什么好处呢?
假如你插入时的数据基本随机,那么你建立的二叉查找树应该是基本平衡的。所谓平衡,就是这棵树的每个叶子节点的深度都基本相同。如果一棵二叉查找树基本平衡,那么它将会有以下好的性质:
- 查找一个值的时间约为O(log(n))
- 插入一个值的时间约为O(log(n))
而且它的代码也非常容易完成,每个操作只需要一个小