左式堆是一种很有意思的二叉树,他与二叉堆即优先队列一样,具有堆序性质,唯一的区别在于他并非完全的平衡,而是偏左的,对任意一个节点x,左儿子的零路径长至少与右儿子的零路径长一样大,所谓的零路径长是从x到一个不具有两个儿子的节点的最短路径长:
如下:
只有左边的才是左式堆,因为左树的左儿子与右儿子的零路径长一样大,右边的不是左式堆,因为1*的左儿子的零路径长为0,而右儿子的零路径长为1,
下面就是一个很好的左式堆:
左式堆虽然没有完全二叉堆那么平衡,但是可以证明,他对于插入,删除与查找最小值与完全二叉堆是一个级别的,更重要的是他能有效的支持堆的合并操作,两个堆的合并
他能做到O(log(n)),这是完全二叉堆所没有的。
左式堆的实现难点在于合并操作,只要实现了合并操作,插入与删除都可以用合并操作实现,下面就是我的C++代码实现:
//leftheap.h
#ifndef LEFTHEAP_H
#define LEFTHEAP_H
template<class Comparable>
class leftheap
{
public:
leftheap(){root=NULL;}
leftheap(const leftheap &rhs)
{
this=rhs;
}
~leftheap()
{
if(root!=NULL)
makeEmpty(root);
}
leftheap & operator =(const leftheap &rhs)
{
if(this!=&rhs)
root=clone(rhs.root);
return *this;
}
bool isEmpty()const
{
return root==NULL;
}
const Comparable & findMin()const
{
return root->element;
}
void insert(const Comparable x)
{
root=merge(new leftheapNode(x),root);
}
void deleteMin()
{
if(!isEmpty())
{
leftheapNode *old=root;
root=merge(root->left,root->right);
delete old;
}
}
void deleteMin(Comparable &x)
{
x=findMin();
deleteMin();
}
void makeEmpty()
{
makeEmpty(root);
}
void merge(leftheap &rhs)
{
if(this==&rhs)
return;
root=merge(root,rhs.root);
rhs.root=NULL;
}
void print()
{
print(root);
}
private:
struct leftheapNode
{
Comparable element;
leftheapNode *left;
leftheapNode *right;
int npl;
leftheapNode(const Comparable &ele,leftheapNode *lt=NULL,leftheapNode *rt=NULL,int x=0)
:element(ele),left(lt),right(rt),npl(x){}
};
leftheapNode *root;
leftheapNode *merge(leftheapNode *h1,leftheapNode *h2 )
{
if(h1==NULL)
return h2;
if(h2==NULL)
return h1;
if(h1->element<h2->element)
return merge1(h1,h2);
else
return merge1(h2,h1);
}
leftheapNode *merge1(leftheapNode *h1,leftheapNode *h2 )
{
if(h1->left==NULL)
h1->left=h2;
else
{
h1->right=merge(h1->right,h2);
if(h1->left->npl<h1->right->npl)
swapChildren(h1);
h1->npl=h1->right->npl+1;
}
return h1;
}
void swapChildren(leftheapNode *h1)
{
if(h1!=NULL)
{
leftheapNode *h=h1->left;
h1->left=h1->right;
h1->right=h;
}
}
void makeEmpty(leftheapNode *h)
{
if(h==NULL)
return;
makeEmpty(h->left);
makeEmpty(h->right);
delete h;
}
void print(leftheapNode * t,int i=0)const
{
if(t!=NULL)
{
print(t->left,i+1);
for(int j=0;j<i;j++)
cout<<" ";
cout<<t->element<<endl;
print(t->right,i+1);
}
}
leftheapNode *clone(leftheapNode *t)
{
if(t==NULL)
return NULL;
return new leftheapNode(t->element,clone(t->left),clone(t->right),t->npl);
}
};
#endif
#include<iostream>
#include<cstdio>
using namespace std;
#include"leftheap.h"
int main()
{
freopen("out.txt","w",stdout);
leftheap<int> LH;
int min;
for(int i=0;i<150;i++)
LH.insert(i);
for(int i=0;i<100;i++)
{
LH.deleteMin(min);
cout<<min<<" ";
}
cout<<endl;
LH.print();
cout<<endl;
fclose(stdout);
return 0;
}
输出结果为:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
141
119
142
107
131
124
132
102
137
121
138
111
127
126
128
103
133
123
148
134
116
147
112
100
114
110
149
115
104
139
120
146
140
117
129
125
145
130
113
105
135
122
144
136
118
143
109
106
101
108
可以看到,他的确是具有堆序性质,而且还是很平衡的,还有,我的main函数虽然没有测试merge操作,但其实插入与删除我都是用merge操作实现的,所以没什么问题!