左式堆及相关操作

左式堆

  • 左式堆同样是一种堆结构满足堆序性质。左式堆是一种趋向不平衡的二叉树。
  • 零路径长(Null Path Length, NPL):节点X到一个没有两个孩子的最短路径长。
  • 具有0个或1个孩子的节点的NPL为0,空节点NPL为-1。
  • 任一节点的NPL比它孩子的NPL的最小值多1。且其左孩子的NPL大于或等于右孩子的NPL,这使得树偏向左增加深度。
  • 在右路径上有r个节点的左式树必然至少有 2r1 2 r − 1 个节点。

左式堆的基本结构

  • 采用指针构造,每个节点为一个树节点包含:关键字值,左孩子域,右孩子域以及额外的零路径长信息。
typedef struct Node {   // 定义左式堆的结点结构
    ElemType data;      // 节点中的数据
    struct Node* left;  // 左孩子
    struct Node* right; // 右孩子
    int Npl;            // 节点的零路径长
}TreeNode, *LeftHeap;

左式堆的合并操作

  • 合并是左式堆的基本操作,采用递归的方式进行。
  • 首先将具有大的根值的堆1与具有小的根植堆2的右子树合并成堆3。
  • 将合并好的堆3与堆2合并(堆3成为堆2的右孩子)成堆4。整个过程递归进行,且保证满足堆序性。
  • 堆4的右子树比左子树深,最后一步将堆4的左右子树互换得到堆5,并更新NPL。

合并操作的驱动函数

LeftHeap Merge(LeftHeap LH1, LeftHeap LH2)      // 合并左式堆的驱动函数
{
    if (LH1 == nullptr)
        return LH2;
    if (LH2 == nullptr)
        return LH1;
    if (LH1->data < LH2->data)
        return Merge1(LH1, LH2);
    else
        return Merge1(LH2, LH1);
}

合并操作的实现函数

LeftHeap Merge1(LeftHeap LH1, LeftHeap LH2)
{
    if (LH1->left == nullptr)           // 单节点,左孩子为空而Npl=0保证了右孩子也为空
    {
        LH1->left = LH2;                // 直接将LH2赋给LH1的左孩子
    }
    else
    {   // LH1不是单节点,
        LH1->right = Merge(LH1->right, LH2);    // 则,先让LH1的右孩子与LH2合并
        if (LH1->left->Npl < LH1->right->Npl)       // 合并完之后,如果LH1左孩子的零路径长小于右孩子的零路径长,不满足左式堆的条件
        {   // 交换左右孩子
            LeftHeap temp = LH1->left;
            LH1->left = LH1->right;
            LH1->right = temp;
        }
        LH1->Npl = LH1->right->Npl + 1;             // 更新LH1的零路径值
    }
    return LH1;
}

左式堆的插入操作

  • 插入是合并的特殊情况,即合并左式堆与一个单节点。
void insert(LeftHeap &LH, ElemType x)
{
    TreeNode* p = new TreeNode;     // 申请一个单节点用于储存x的值
    p->data = x;
    p->left = p->right = nullptr;
    p->Npl = 0;
    LH = Merge(LH, p);              // 合并LH与p,这里把单节点看成一个树
}

左式堆的删除操作

  • 删除操作同样基于合并操作,删除根节点,合并左右子树。
ElemType DeleteMin(LeftHeap &LH)            // 删除优先队列最小值
{
    LeftHeap Left = LH->left;       // 把左式堆分成两个左右两个子左式堆
    LeftHeap Right = LH->right;
    ElemType x = LH->data;
    delete LH;      // 释放根节点
    LH = Merge(Left, Right);                // 合并左右两个子堆
    return x;                       // 返回删除的最小值
}

附左式堆实现及相关操作C/C++

#include<iostream>

using namespace std;

typedef int ElemType;
typedef struct Node {   // 定义左式堆的结点结构
    ElemType data;      // 节点中的数据
    struct Node* left;  // 左孩子
    struct Node* right; // 右孩子
    int Npl;            // 节点的零路径长
}TreeNode, *LeftHeap;
LeftHeap Merge(LeftHeap LH1, LeftHeap LH2);
LeftHeap Merge1(LeftHeap LH1, LeftHeap LH2);

bool isEmpty(LeftHeap LH)   //  判断堆是否为空
{
    return LH == nullptr;
}

LeftHeap Merge(LeftHeap LH1, LeftHeap LH2)      // 合并左式堆的驱动函数
{
    if (LH1 == nullptr)
        return LH2;
    if (LH2 == nullptr)
        return LH1;
    if (LH1->data < LH2->data)
        return Merge1(LH1, LH2);
    else
        return Merge1(LH2, LH1);
}

LeftHeap Merge1(LeftHeap LH1, LeftHeap LH2)
{
    if (LH1->left == nullptr)           // 单节点,左孩子为空而Npl=0保证了右孩子也为空
    {
        LH1->left = LH2;                // 直接将LH2赋给LH1的左孩子
    }
    else
    {   // LH1不是单节点,
        LH1->right = Merge(LH1->right, LH2);    // 则,先让LH1的右孩子与LH2合并
        if (LH1->left->Npl < LH1->right->Npl)       // 合并完之后,如果LH1左孩子的零路径长小于右孩子的零路径长,不满足左式堆的条件
        {   // 交换左右孩子
            LeftHeap temp = LH1->left;
            LH1->left = LH1->right;
            LH1->right = temp;
        }
        LH1->Npl = LH1->right->Npl + 1;             // 更新LH1的零路径值
    }
    return LH1;
}

void insert(LeftHeap &LH, ElemType x)
{
    TreeNode* p = new TreeNode;     // 申请一个单节点用于储存x的值
    p->data = x;
    p->left = p->right = nullptr;
    p->Npl = 0;
    LH = Merge(LH, p);              // 合并LH与p,这里把单节点看成一个树
}

ElemType DeleteMin(LeftHeap &LH)            // 删除优先队列最小值
{
    LeftHeap Left = LH->left;       // 把左式堆分成两个左右两个子左式堆
    LeftHeap Right = LH->right;
    ElemType x = LH->data;
    delete LH;      // 释放根节点
    LH = Merge(Left, Right);                // 合并左右两个子堆
    return x;                       // 返回删除的最小值
}

int main()
{
    const int rawdata[] = { 19, 13, 9, 8, 23, 39, 4, 2, 75, 100, 43, 58 };
    int tablesize = 12;

    LeftHeap myLeftHeap = nullptr;      // 初始化左式堆为空指针

    for (int i = 0;i < sizeof(rawdata) / sizeof(int);i++)
    {
        insert(myLeftHeap, rawdata[i]);     // 向堆中插入给定数据
    }

    cout << "Prior Deque from the Heap : \n";   // 依次优先出队列
    while (!isEmpty(myLeftHeap))
    {
        cout << DeleteMin(myLeftHeap) << " ";
    }
    cout << endl;

    delete myLeftHeap;
    system("pause");
    return 0;
}
  • 操作实现结果
Prior Deque from the Heap :
2 4 8 9 13 19 23 39 43 58 75 100

参考资料

Mark Allen Weiss: 数据结构与算法分析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值