左式堆(leftist heap):
由左结点形成的长路径构成的树(而且实际上更便于合并操作)称之为左式堆。
零路径长(null path length):
npl(x)定义为从x到一个不具有两个儿子结点的最短路径的长。因此具有0个或一个儿子的结点的npl(x) = 0。
左式堆的性质:
1)对于堆中的每一个结点X,左儿子的路径长至少和右儿子的路经长一样大;
2)在右路径上有r个结点的左式堆必然至少有个结点【数学归纳法】;
左式堆的基本操作:
合并(merge):插入只是合并的一种特殊情况;
1. 如果两个堆有一个是空堆,可以直接返回非空堆;
2.递归合并具有较大根节点的堆和较小根节点的右子堆;
3.交换较小根节点的堆的左右孩子并更新零长路径;
合并过程如下图:
两个左式堆和
将
与
右子堆合并 将
拼接到
右子堆
交换根节点左右孩子后的结果
实例:建立左式堆,实现插入、删除最小值、查询最小值、打印输出等功能。【注:此处为最小堆方式】
1、heap.h
//heap.h
#ifndef HEAP_H_
#define HEAP_H_
#include<iostream>
#include<vector>
#include<algorithm>
using std::cout;
using std::endl;
using std::vector;
template<class T>
struct LeftistNode{
T element;
LeftistNode *left;
LeftistNode *right;
int npl;
LeftistNode(const T &e, LeftistNode<T> *l = NULL, LeftistNode<T> *r = NULL, int n = 0):element(e), left(l), right(r), npl(n){
};
};
template<class T>
class LeftistHeap{
public:
//LeftistHeap constuctor
LeftistHeap():root(NULL){
};
//LeftistHeap constuctor
LeftistHeap(const LeftistHeap &heap){
root = clone(heap -> root);
};
//LeftistHeap destructor
~LeftistHeap(){
makeEmpty();
};
//judge whether the heap is empty
bool isEmpty() const{
return root == NULL;
};
//find the minmum element in heap
const T &findMin() const{
if(root != NULL){
return root -> element;
}
return (T)NULL;
};
//insert value
void insert(const T &value){
root = merge(new LeftistNode<T>(value), root);
};
//delete the minmum
void deleteMin(){
if(isEmpty()){
cout << " the heap is already empty !" << endl;
}
LeftistNode<T> *node = root;
root = merge(root -> left, root -> right);
delete node;
};
//delete the minItem
void deleteMin(T &minItem){
minItem = findMin();
deleteMin();
}
//make empty of the heap
void makeEmpty(){
reclaimMemory(root);
root = NULL;
};
//excute merge operation
void merge(LeftistHeap<T> &heap){
if(this == &heap){
return;
}
root = merge(root, heap.root);
heap.root = NULL;
};
const LeftistHeap<T> & operator=(const LeftistHeap<T> &heap){
if(this != &heap){
makeEmpty();
root = clone(heap.root);
}
return *this;
};
//print the heap
void print(){
LeftistHeap heap;
vector<T> v;
while(this -> root){
v.push_back(this -> findMin());
heap.insert(this -> findMin());
this -> deleteMin();
}
for(int i = 0; i < v.size(); i++){
cout << v[i] << " ";
}
cout << endl;
*this = heap;
};
private:
LeftistNode<T>* merge(LeftistNode<T> *h1, LeftistNode<T> *h2);
LeftistNode<T>* merge1(LeftistNode<T> *h1, LeftistNode<T> *h2);
void swapChildren(LeftistNode<T> *heap);
void reclaimMemory(LeftistNode<T> *heap);
LeftistNode<T>* clone(const LeftistNode<T> *heap);
private:
LeftistNode<T>* root;
};
//merge root
template<class T>
LeftistNode<T>* LeftistHeap<T>::merge(LeftistNode<T> *h1, LeftistNode<T> *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);
}
}
template<class T>
LeftistNode<T>* LeftistHeap<T>::merge1(LeftistNode<T> *h1, LeftistNode<T> *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;
}
template<class T>
void LeftistHeap<T>::swapChildren(LeftistNode<T> *heap){
if(heap != NULL){
LeftistNode<T> *temp = heap -> left;
heap -> left = heap -> right;
heap -> right = temp;
}
}
template<class T>
void LeftistHeap<T>::reclaimMemory(LeftistNode<T> *heap){
if(heap != NULL){
reclaimMemory(heap -> left);
reclaimMemory(heap -> right);
delete heap;
}
}
template<class T>
LeftistNode<T>* LeftistHeap<T>::clone(const LeftistNode<T> *heap){
if(heap == NULL){
return NULL;
}
return new LeftistNode<T>(heap -> element, clone(heap -> left), clone(heap -> right), heap -> npl);
}
#endif
2、main.cpp
//main.cpp
#include<iostream>
#include"heap.h"
using namespace std;
int main(){
int arr1[8] = {3, 10, 8, 21, 14, 17, 23, 26};
int arr2[8] = {6, 12, 7, 18, 24, 37, 18, 33};
LeftistHeap<int> *h1 = new LeftistHeap<int>();
LeftistHeap<int> *h2 = new LeftistHeap<int>();
cout << "********* insert ************" << endl;
for(int i = 0; i < 8; i++){
h1 -> insert(arr1[i]);
h2 -> insert(arr2[i]);
}
cout << "********* print ************" << endl;
cout << " the info in h1 as follows : " << endl;
h1 -> print();
cout << " the info in h2 as follows : " << endl;
h2 -> print();
cout << "********* merge ************" << endl;
h1 -> merge(*h2);
h1 -> print();
cout << "********* deleteMin ************" << endl;
int minItem;
h1 -> deleteMin(minItem);
cout << " the minmum value in h1 is " << minItem << endl;
cout << " done ." << endl;
return 0;
}
practice makes perfect !