博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
左式堆
阅读量:6524 次
发布时间:2019-06-24

本文共 3497 字,大约阅读时间需要 11 分钟。

简介

 

设计一种堆结构像二叉堆那样高效的支持合并操作而且只使用一个数组似乎很困难。原因在于,合并似乎需要把一个数组拷贝到另一个数组中去,对于相同大小的堆,这将花费O(N)。正因为如此,所有支持高效合并的高级数据结构都需要使用指针。

像二叉堆那样,左式堆也有结构性和堆序性。不仅如此,左式堆也是二叉树,它和二叉堆之间的唯一区别在于:左式堆不是理想平衡的,而实际上是趋向于非常不平衡。

左式堆性质

 

把任意节点X的零路径长(null path length, NPL)Npl(X)定义为从X到一个没有两个儿子的节点的最短路径长。因此,具有0个或1个儿子的节点的Npl值为0,而Npl(NULL)=-1。注意,任意节点的零路径长比它的各个儿子节点的最小值多1。

左式堆的性质是:对于堆中的每一个节点X,左儿子的零路径长至少与右儿子的零路径长一样大。因此,下图1中,左边的二叉树是左式堆,而右边的二叉树则不是。这个性质使左式堆明显更偏重于使树向左增加深度,左式堆的名称也由此而来。

图1:两棵树的零路径长,只有左边的树是左式堆

左式堆操作

 

左式堆的基本操作是合并(Merge),注意,插入只是合并的特殊情形。因为可以把插入看成是单节点堆与一个大的堆的Merge。对于合并操作,主要采取的是递归解法。如图2所示,两个左式堆H1,H2,注意,最小元在根处。除数据,左指针,右指针外,每个单元还需要有一个指示零路径长的项。

图2:两个左式堆H1,H2

如果这两个堆有一个是空的,那么可以直接返回。否则,为了合并两个堆,需要比较它们的根。首先,将具有大的根值的堆与具有较小的根值的堆的右子树堆合并。在本例中,我们递归的将H2与H1在8处的右子树堆合并,得到如图3中的堆。

图3:将H2与H1的右子树堆合并的结果

如果直接将图3中的堆作为H1的右儿子,如图4所示,那么新的H1虽然满足堆序性质,但是它不是左式堆,因为左子树的零路径长为1,而根的右儿子的零路径长为2.因此,左式堆的性质在根处被破坏。不过,很容易看到,树的其余部分必然是左式堆,由于递归步骤,根的右子树也是左式堆。根的左子树没发生变化,必然也是左式堆。这样一来,只需要对根进行调整就可以了。使整个树是左式堆的做法如下:只要交换根的左儿子和右儿子,并更新零路径长,就完成了Merge。如图5所示:

图4:H1接上图3中的左式堆作为右儿子的结果

图5:交换H1的根的儿子得到的结果

上面提到,我们可以通过把被插入项看成单节点并执行一次Merge来完成插入。为了执行DeleteMin,只要除掉根而得到两个堆,然后再将这两个堆合并。因此执行一次DeleteMin操作的时间为O(logN)。

代码实现

LeafHeap.h

typedef int ElementType;#ifndef _LeafHeap_Hstruct TreeNode;typedef struct TreeNode *PriorityQueue;PriorityQueue Initialize(void);ElementType FindMin(PriorityQueue H);int IsEmpty(PriorityQueue H);PriorityQueue Merge(PriorityQueue H1,PriorityQueue H2);#define Insert(X,H) (H=Insert1((X),H))PriorityQueue Insert1(ElementType X,PriorityQueue H);PriorityQueue DeleteMin(PriorityQueue H);#endifstruct TreeNode{    ElementType Element;    PriorityQueue left;    PriorityQueue right;    int Np1;};

LeftHeap.c

#include "LeftHeap.h"#include "fatal.h"PriorityQueue Initialize(void){    PriorityQueue H=malloc(sizeof(struct TreeNode));    H->left=H->right=NULL;    H->Np1=-1;    H->Element=0;    return H;}ElementType FindMin(PriorityQueue H){    if(IsEmpty(H))        return -1;    return H->Element;}int IsEmpty(PriorityQueue H){    return H==NULL;}static void SwapChildren(PriorityQueue H){    PriorityQueue temp;    temp=H->left;    H->left=H->right;    H->right=temp;}static PriorityQueue Merge1(PriorityQueue H1, PriorityQueue H2){    if(H1->left==NULL)        H1->left=H2;    else    {        H1->right=Merge(H1->right,H2);        if(H1->left->Np1
right->Np1) SwapChildren(H1); H1->Np1=H1->right->Np1+1; } return H1;}PriorityQueue Merge(PriorityQueue H1, PriorityQueue H2){ if(H1==NULL) return H2; else if(H2==NULL) return H1; if(H1->Element
Element) return Merge1(H1,H2); else return Merge1(H2,H1);}PriorityQueue Insert1(ElementType X, PriorityQueue H){ PriorityQueue SingleNode; SingleNode=malloc(sizeof(struct TreeNode)); if(SingleNode==NULL) FatalError("Out of space!!!"); else { SingleNode->left=SingleNode->right=NULL; SingleNode->Np1=0; SingleNode->Element=X; H=Merge(SingleNode,H); } return H;}PriorityQueue DeleteMin(PriorityQueue H){ PriorityQueue LeftHeap,RightHeap; if(IsEmpty(H)) { Error("Priority queue is empty"); return H; } LeftHeap=H->left; RightHeap=H->right; free(H); return Merge(LeftHeap,RightHeap);}

UseLeftHeap.c

#include"LeftHeap.h"#include
int main(){ int i; PriorityQueue H; H=Initialize(); for(i=0;i<10;i++) H=Insert1(i,H); for(i=0;i<10;i++) { printf("Element : %d ",H[i].Element); } return 0;}

 

转载地址:http://ibjbo.baihongyu.com/

你可能感兴趣的文章
java Windows7 下环境变量设置
查看>>
NBU异构还原Oracle完整备份的一些总结
查看>>
freeBSD安装详细讲解
查看>>
WSFC2016 VM弹性与存储容错
查看>>
文档管理,文本编辑控件TX Text Control .NET for WPF
查看>>
复习 Python 匿名函数 内建函数
查看>>
Security Identifiers | Win SRV2016 SID Change 修改
查看>>
看看来自日本的扫描,做网站需要注意的
查看>>
JDK 1.7+Android SDK+IntelliJ IDEA 13+Genymotion 安卓开发环境部署
查看>>
钓鱼邮件***防范指南
查看>>
session_start()放置位置的不正确引发的ROOT常量 未定义的错误
查看>>
如何设定VDP同时备份的任务数?
查看>>
ipsec的***在企业网中的经典应用
查看>>
过来人谈《去360还是留在百度?》
查看>>
mysql备份工具innobackupex,xtrabackup-2.1安装,参数详解
查看>>
【复制】slave筛选复制之二(create/drop table语句)
查看>>
Movie Store OpenCart 自适应主题模板 ABC-0249
查看>>
mytop-MySQL监控工具
查看>>
RedHat linux YUM本地制作源
查看>>
apache端口占用问题
查看>>