左式堆(左偏树)

左式堆又叫做左偏树, 是一种合并高效的堆, 左式堆的insert以及
deleteMin等操做都是以merge操做为基础的。
merge时间复杂度能够达到O(logN)

左式堆使用二叉树的结构实现, 相比于二叉树,
其结点上增长了一个NPL (null path length)属性,
它指的是从该结点到达一个没有两个孩子的结点的最短距离,
叶节点的NPL为0,NULL节点的NPL为-1, 满足如下3个性质

1. 结点的键值小于等于其左右孩子的键值(小根性)
2. 结点的左孩子的npl不小于其右孩子的NPL(左偏性)
3. 结点的距离等于其右孩子的NPL+1

合并核心操作:
(1) 如果合并一个空左式堆与一个非空左式堆,返回非空左式堆。
(2) 如果两个左式堆都非空,那么比较两个根节点,取较小堆的根节点为合并后堆的根节点,
然后将这个根的左孩子作为合并后堆的左儿子,递归地合并其右儿子与另一个堆,作为合并后的堆的右孩子。
(3) 如果新堆的右孩子的NPL > 左孩子的NPL,则交换其左右孩子。
(4) 设置新堆的根节点的NPL = 右子堆NPL + 1

针对键值为正数的顺序实现
#include <iostream>
#include <queue>
#include <vector>

struct LHNode
{
    int ls;
    int rs;
    int d;
    int val;
    int fa;
    LHNode(int v)
        : val(v), d(0), ls(0), rs(0), fa(0) {}
    LHNode()
        : val(0), d(-1), ls(0), rs(0), fa(0) {}
};

const int SIZE = 10e2+2;
LHNode t[SIZE];

int merge(int x, int y) 
{
    if (!x || !y) return x | y;  // 若一个堆为空则返回另一个堆
    if (t[x].val > t[y].val)     // 取值较小的作为根
        std::swap(x, y);  
    t[x].rs = merge(t[x].rs, y);       // 递归合并右儿子与另一个堆
    if (t[t[x].rs].d > t[t[x].ls].d)
        std::swap(t[x].ls, t[x].rs);   // 若不满足左偏性质则交换左右儿子
    t[x].d = t[t[x].rs].d + 1;         // 更新dist
    return x;
}

/****************
删除任意结点的核心思想:
先将左右孩子合并,然后自底向上更新NPL,不满足左偏性时交换左右孩子,
当NPL无需更新时结束递归;
如果删除根,直接合并左右孩子就行。
****************/
void remove(int x)
{
    int q = t[x].fa;                   // p is x's parent
    int p = merge(t[x].ls, t[x].rs);   // q is the new tree's root
    t[p].fa = q;

    if (q != 0 && t[q].ls == x)        // if left, link to left
        t[q].ls = p;
    if (q != 0 && t[q].rs == x)        // if right, link to right
        t[q].rs = p;

    while (q != 0)
    {
        if (t[t[q].ls].d < t[t[q].rs].d)
            std::swap(t[q].ls, t[q].rs);
        if (t[t[q].rs].d + 1 == t[q].d)
            break;
        else
            t[q].d = t[t[q].rs].d + 1;

        q = t[q].fa;
    }
}

void layer(int x)
{
    std::queue<int> qu;
    std::vector<int> vec;
    if (x != 0)
        qu.push(x);
    while (!qu.empty())
    {
        vec.clear();
        int j =0 , size = qu.size();
        for (j = 0; j < size; ++j)
        {
            int i = qu.front();
            qu.pop();
            vec.push_back(i);
            if (i != 0)
            {
                //if (t[i].ls != 0)
                qu.push(t[i].ls);
                //if (t[i].rs != 0)
                qu.push(t[i].rs);
            }
        }

        for (j = 0; j < vec.size(); ++j)
        {
            if (vec[j] == 0)
                std::cout << "#  ";
            else
                std::cout << vec[j] << "(" << t[vec[j]].d << ")" << "  ";
        }
        std::cout << std::endl;
    }
}

int main()
{
    int arr1[] = {10, 24, 12, 30, 36, 20, 16, 40};
    int arr2[] = {11, 15, 13, 19, 21, 17, 23};
    int i = 0;

    int root1 = 0;
    for (i = 0; i < sizeof(arr1) / sizeof(int); ++i)
    {
        t[arr1[i]] = LHNode(arr1[i]);
        root1 = merge(root1, arr1[i]);
    }
    std::cout << "root1: " << root1 << std::endl;
    layer(root1);
    
    int root2 = 0;
    for (i = 0; i < sizeof(arr2) / sizeof(int); ++i)
    {
        t[arr2[i]] = LHNode(arr2[i]);
        root2 = merge(root2, arr2[i]);
    }
    std::cout << "root2: " << root2 << std::endl;
    layer(root2);

    root1 = merge(root1, root2);
    std::cout << "new tree: " << root1 << std::endl;
    layer(root1);

    std::cout << "after remove 11,new root:  " << root1 << std::endl;
    remove(11);
    layer(10);

    return 0;
}

root1: 10
10(2)
12(1)  16(1)
30(0)  36(0)  20(0)  40(0)
#  #  #  #  24(0)  #  #  #
#  #
root2: 11
11(2)
13(1)  15(1)
19(0)  21(0)  17(0)  23(0)
#  #  #  #  #  #  #  #
new tree: 10
10(2)
11(2)  12(1)
13(1)  15(1)  30(0)  36(0)
19(0)  21(0)  16(1)  17(0)  #  #  #  #
#  #  #  #  20(0)  23(0)  #  #
24(0)  #  40(0)  #
#  #  #  #

after remove 11?new root:  10
10(2)
13(1)  12(1)
15(1)  19(0)  30(0)  36(0)
16(1)  17(0)  #  #  #  #  #  #
20(0)  23(0)  21(0)  #
24(0)  #  40(0)  #  #  #
#  #  #  #

左偏堆链式存储:
#include <iostream>
#include <queue>
#include <vector>

struct LLHNode
{
    LLHNode *ls;
    LLHNode *rs;
    int d;
    int val;
    LLHNode *fa;
    LLHNode(int v)
        : val(v), d(0), ls(nullptr), rs(nullptr), fa(nullptr) {}
    LLHNode()
        : val(0), d(-1), ls(nullptr), rs(nullptr), fa(nullptr) {}
};

class LeftLinkHeap
{
public:
    LeftLinkHeap() : m_root(nullptr) {}
    ~LeftLinkHeap();
    void insert(int k);
    void remove(int k);
    void layer();
    void merge(LeftLinkHeap* other);

private:
    void destroy(LLHNode *t);
    void swap(LLHNode* &l, LLHNode* &r);
    LLHNode* merge(LLHNode* &x, LLHNode* &y);
    LLHNode* search(int x);

private:
    LLHNode *m_root;
};

LeftLinkHeap::~LeftLinkHeap()
{
    destroy(m_root);
}

void LeftLinkHeap::destroy(LLHNode *t)
{
    if (t != nullptr)
    {
        destroy(t->ls);
        destroy(t->rs);
        delete t;
        t = nullptr;
    }
}

void LeftLinkHeap::swap(LLHNode* &l, LLHNode* &r)
{
    LLHNode* t = l;
    l = r;
    r = t;
}

LLHNode* LeftLinkHeap::merge(LLHNode* &x, LLHNode* &y)
{
    if (x == nullptr)
        return y;
    if (y == nullptr)
        return x;

    if (x->val > y->val)
        swap(x, y);

    x->rs = merge(x->rs, y);
    x->rs->fa = x;

    if (x->ls == nullptr || x->rs->d > x->ls->d)
        swap(x->ls, x->rs);

    if (x->rs == nullptr)
        x->d = 0;
    else
        x->d = x->rs->d + 1;

    return x;
}

void LeftLinkHeap::merge(LeftLinkHeap* other)
{
    m_root = merge(m_root, other->m_root);
}

void LeftLinkHeap::insert(int k)
{
    LLHNode *pNode = new LLHNode(k);
    m_root = merge(m_root, pNode);
}

void LeftLinkHeap::layer()
{
    std::queue<LLHNode *> qu;
    if (m_root != nullptr)
        qu.push(m_root);
    
    while (!qu.empty())
    {
        int size = qu.size();
        for (int i = 0; i < size; ++i)
        {
            LLHNode *t = qu.front();
            qu.pop();
            if (t != nullptr)
            {
                std::cout << t->val << "  ";
                //if (t->ls != nullptr)
                    qu.push(t->ls);
                //if (t->rs != nullptr)
                    qu.push(t->rs);
            }
            else
                std::cout << "#  ";
        }
        std::cout << std::endl;
    }
}

LLHNode* LeftLinkHeap::search(int x)
{
    std::queue<LLHNode *> qu;
    if (m_root != nullptr)
        qu.push(m_root);
    while (!qu.empty())
    {
        LLHNode *t = qu.front();
        qu.pop();
        if (t->val == x)
            return t;
        if (t->ls != nullptr)
        {
            if (t->ls->val == x)
                return t->ls;
            else if (t->ls->val < x)
                qu.push(t->ls);
        }

        if (t->rs != nullptr)
        {
            if (t->rs->val == x)
                return t->rs;
            else if (t->rs->val < x)
                qu.push(t->rs);
        }
    }

    return nullptr;
}

void LeftLinkHeap::remove(int k)
{
    LLHNode *t = search(k);
    LLHNode *parent = t->fa;
    t = merge(t->ls, t->rs);

    if (parent == nullptr)
        m_root = t;
    else
    {
        if (parent->ls->val == k)
            parent->ls = t;
        if (parent->rs->val == k)
            parent->rs = t;
    }

    while (parent != nullptr)
    {
        if (parent->rs->d > parent->ls->d)
            swap(parent->ls, parent->rs);
        if (parent->d == parent->rs->d + 1)
            break;
        else
            parent->d = parent->rs->d + 1;
        parent = parent->fa;
    }
}

int main()
{
    int arr1[] = { 10, 24, 12, 30, 36, 20, 16, 40 };
    int arr2[] = { 11, 15, 13, 19, 21, 17, 23 };

    std::cout << "create one leftlistlheap1 " << std::endl;
    LeftLinkHeap llheap;
    int i = 0;
    for (i = 0; i < sizeof(arr1) / sizeof(int); ++i)
        llheap.insert(arr1[i]);
    llheap.layer();

    std::cout << "create leftlistlheap2 " << std::endl;
    LeftLinkHeap other;
    for (i = 0; i < sizeof(arr2) / sizeof(int); ++i)
        other.insert(arr2[i]);
    other.layer();

    std::cout << "merge leftlistlheap1 and leftlistlheap2 " << std::endl;
    llheap.merge(&other);
    llheap.layer();

    std::cout << "after remove 11" << std::endl;
    llheap.remove(11);
    llheap.layer();

    return 0;
}

create one leftlistlheap1
10
12  16
30  36  20  40
#  #  #  #  24  #  #  #
#  #
create leftlistlheap2
11
13  15
19  21  17  23
#  #  #  #  #  #  #  #
merge leftlistlheap1 and leftlistlheap2
10
11  12
13  15  30  36
19  21  16  17  #  #  #  #
#  #  #  #  20  23  #  #
24  #  40  #
#  #  #  #
after remove 11
10
13  12
15  19  30  36
16  17  #  #  #  #  #  #
20  23  21  #
24  #  40  #  #  #
#  #  #  #

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值