配对堆学习笔记

由于博主很弱,只会打板子,请见谅

配对堆

一种极其好写又极其快速的堆

先看复杂度

空间复杂度: Θ ( n ) \Theta(n) Θ(n)
时间复杂度:
插入: Θ ( 1 ) \Theta(1) Θ(1)
合并: Θ ( 1 ) \Theta(1) Θ(1)
查询最值: Θ ( 1 ) \Theta(1) Θ(1)
删除元素: O ( l o g   n ) O(log\,n) O(logn)(均摊)
修改元素:下界 Ω ( l o g   l o g   n ) \Omega(log\,log\,n) Ω(loglogn),上界 O ( 2 2 l o g   l o g   n ) O(2^{2\sqrt{log\,log\,n}}) O(22loglogn )(均摊)?反正就是 O ( O( O(玄学 ) ) )

在进操作之前,先看看配对堆的结构

强行模仿STL源码码风警告

不熟练的面向对象及封装警告

配对堆是一种堆有序多叉树。根据要完成的操作,可以给出对该类的定义

template<typename _Tp,typename _Cmp=std::less<_Tp> >
class pairing_heap:private _Cmp
{
   
    typedef _Tp value_type;
    typedef _Cmp compare;
    private:
        struct Node;//单个元素结点
        Node* _root;//根指针
        size_t s;//记录堆的大小
        Node* merge(Node*,Node*);//合并两个堆的内部实现
        Node* __pop();//删除函数的内部实现
    public:
        struct iterator;//迭代器
        iterator push(const _Tp&);//在堆中压入新元素
        _Tp top()const;//取堆顶
        iterator pop();//删除堆顶元素
        void join(pairing_heap&);//合并两个堆
        bool modify(const iterator&,const _Tp&);//将某位置的值修改
        size_t size();//不做解释
        bool empty();
};

对每个结点,需维护其父亲及所有的儿子。为了方便在修改元素时将结点分离出来,这里采用双向链表来维护其儿子。具体地讲,父亲的child指针指向第一个儿子,同时每个结点又带有指向右兄弟的指针域。每个结点还有一个“左结点”:对于有左兄弟的结点即为左兄弟,否则为父结点。这种存储方法被称为“左儿子右兄弟”(似乎广义表就是这么存的?)。
来看看图
这是原来的堆

这是堆的实际存储方式

还是很好理解的QWQ

结点的结构体

template<typename _Tp,typename _Cmp>
struct
pairing_heap<_Tp,_Cmp>::Node
{
   
    _Tp value;
    Node *left_node,*child,*sibling;
    //left_node即“左结点”,child指向最左侧的儿子,sibling指向右兄弟
    Node(const _Tp& val=_Tp()):
        value(val),
        left_node(NULL),
        child(NULL),
        sibling(NULL) {
   }
};

为了修改权值,再写出指向元素的迭代器

template<typename _Tp,typename _Cmp>
struct
pairing_heap
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值