数据结构-树堆(Treap)

现在给你一个问题,每次右两种操作,第一种操作是向集合中添加一个数x,第二种操作是询问集合中不大于k的最大的数是多少。现在我们不用任何stl里面的容器的情况下,你要怎样解决这个问题呢?一个最暴力的方法是,从一个数组存数,然后每次询问去遍历这个数组,这样每次插入数的时间复杂度是O(1),而查询时间复杂是O(n),所以这种方法对于查询操作比较多时,会很慢.有基础的同学可能会想到用二分去找,但是用二分必须要求整个序列是有序的,所以要保证你的数组是有序的,每次需要把一个数插入到合适的位置,然后把这个数后面的都往后移动一位,这样的话询问时间复杂度是O(logn),但是插入时间复杂度是O(n),这种方法对于插入操作比较多时,也很慢。跟上面暴力的方法相比复杂度没有本质的变化。当然这个问题好像可以用跳表解决,也就是在链表上做二分,当然这个我不会。也不是今天要谈论的内容。学过二叉排序树的同学,也许会想到用二叉排序树来做,这样每次插入的复杂度是树的高度,询问的复杂度也是树的高度。这种方法比上面的两种方法都要高效,但是有一个致命的弱点,就是当所给的序列是一个递增序列时,你的二叉树会退化成一条链,这样每次插入的复杂度和询问的复杂度都是O(n).那么我们有没有一种方法可以避免这种情况呢?答案是有的。就是今天我们要讲的数据结构Treap,树堆,是Tree + Heap的结合体。同时满足二叉排序树和堆的性质。在树堆中每个节点除了值value外另外还加入一个值w,这个值每次初始化时时随机的一个值。value满足二叉排序树的特点,而w满足堆的特点。这样每次插入一个树时,我们按value的值插入,也就是插入之后情况一定时满足二叉排序树的,但是因为我们的w值是随机生成的,所以有可能会不满足堆的性质,不满足怎么办?当然是调整啊,在堆中我们调整的方法是跟父亲节点的值交换,在这里面当然不能也这样做,因为这样会破坏二叉排序树的性质。这里我们调整只能通过旋转根来完成这个工作,这样既不会破坏二叉排序树的性质,也可以调整w,使得其满足堆的性质。旋转有左旋和右旋,左旋是把根的右儿子节点旋转到根,根变成右儿子节点的左孩子,原来右儿子的左儿子节点(如果有的话,也有可能没有)变成原来根节点的右儿子。右旋和左旋类似。这样就完成了调整这个操作。你肯定要问,这样做有什么用?这样做的目的,是通过w的随机性,保证树的平衡性,通俗来说就是是树不要退化成链。你可以看到,Treap这个东西依赖与随机来保证树的平衡,这个东西也是看脸的,但是平均,也就是期望的复杂度是O(logn).下面是一道实际的题目,这个题目的数据比较弱,不用Treap,只用二叉排序树也能过。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值