这是第一篇博客,相信是个不错的开始!
//define the leftist heap struct
typedef struct Leftist pLeftist;
struct Leftist{
int element;
pLeftist left, right;
int npl;
};
//build the merged leftist heap and return it
pLeftist BuildHeap(LeftistQueue q){
Leftist h1, h2;
while(!IsEmpty(q)){
h1 = Dequeue(q);
if(IsEmpty(q))
return h1; //the leftist heap has been built
h2 = Dequeue(q);
Enqueue(q, Merge(h1, h2)); //enqueue the new merged leftist heap
}
return NULL; //there is no leftist heap in queue
}
pLeftist Merge(Leftist h1, Leftist h2){
if(!h1)
return h2;
if(!h2)
return h1;
if(h1->element<h2->element) //compare the element and choose the root
return MergeHeap(h1, h2);
else
return MergeHeap(h2, h1);
}
pLeftist MergeHeap(Leftist h1, Leftist h2){
if(!h1->left){
h1->left = h2; //single node
}else{
h1->right = Merge(h1->right, h2);
if(h1->left->npl<h1->right->npl) //make left child's npl >= right's
SwapChl(h1);
h1->npl = h1->right->npl+1; //make the npl equalling its right child+1
}
return h1; //return the root
}
左式堆而言,较于小根堆
1.合并速度快,O(n)
2.链表比数组带来更多的开销,并且多一个域(npl)
3.代码相对复杂,其实也不复杂
较于leftist heap,有个skew heap,每次合并都左右换一下,不需要(npl),如果数据是随机的,也是一个很不错的选择
有个同学说随机删除堆里的一个元素,这样的方法比较好:
将改点的值置为负无穷,然后冒泡到顶部,再删去顶部,将剩下的两个子树合并。
不过,堆似乎不是用来随机删除节点的。一般指删最小的,以前遇到过一个题目,在最小的三个元素中删除一个特定的,这样就可以在前三层找(应该是7个元素中),然后删,随机删除其中的任意节点得不偿失。
还有,删除任意节点,将其子树合并,合并获得的新树的根放回原来删除节点的位置,这样不是很合理吗,为何要冒泡到最顶部?