斜堆(SkewHeap):
斜堆是左式堆的自调节形式,斜堆和左式堆的关系类似于伸展树和AVL树的关系。斜堆是具有堆序的二叉树,但是不存在对树的结构限制,且不保留零长路径的信息。斜堆的右路径在任何时刻都可以任意长,因此所有操作最坏运行情况为,正如伸展树一样,可以证明(还没证明出来 (┭┮﹏┭┮))对任意M次操作,总的最坏运行情况为
,因此每次操作的摊还开销(amortized cost)为
.
斜堆的基本操作:
合并(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 SkewNode{
T element;
SkewNode<T> *left;
SkewNode<T> *right;
SkewNode(const T &e, SkewNode<T> *l = NULL, SkewNode<T> *r = NULL):element(e), left(l), right(r){
};
};
template<class T>
class SkewHeap{
public:
//LeftistHeap constuctor
SkewHeap():root(NULL){
};
//LeftistHeap constuctor
SkewHeap(const SkewHeap &heap){
root = clone(heap -> root);
};
//LeftistHeap destructor
~SkewHeap(){
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){
SkewNode<T>* temp;
temp = new SkewNode<T>(value, NULL, NULL);
root = merge(root, temp);
};
//delete the minmum
void deleteMin(){
if(isEmpty()){
cout << " the heap is already empty !" << endl;
}
SkewNode<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(SkewHeap<T> *heap){
root = merge(root, heap -> root);
};
const SkewHeap<T> & operator=(const SkewHeap<T> &heap){
if(this != &heap){
makeEmpty();
root = clone(heap.root);
}
return *this;
};
//print the heap
void print(){
SkewHeap 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:
SkewNode<T>* merge(SkewNode<T>* &h1, SkewNode<T>* &h2);
void swapChildren(SkewNode<T>* &h1, SkewNode<T>* &h2);
void reclaimMemory(SkewNode<T> *heap);
SkewNode<T>* clone(const SkewNode<T> *heap);
private:
SkewNode<T>* root;
};
//merge root
template<class T>
SkewNode<T>* SkewHeap<T>::merge(SkewNode<T>* &h1, SkewNode<T>* &h2){
if(h1 == NULL){
return h2;
}
if(h2 == NULL){
return h1;
}
if(h1 -> element > h2 -> element){
swapChildren(h1, h2);
}
SkewNode<T>* temp = merge(h1 -> right, h2);
h1 -> right = h1 -> left;
h1 -> left = temp;
return h1;
}
template<class T>
void SkewHeap<T>::swapChildren(SkewNode<T>* &h1, SkewNode<T>* &h2){
SkewNode<T>* temp = h1;
h1 = h2;
h2 = temp;
}
template<class T>
void SkewHeap<T>::reclaimMemory(SkewNode<T> *heap){
if(heap != NULL){
reclaimMemory(heap -> left);
reclaimMemory(heap -> right);
delete heap;
}
}
template<class T>
SkewNode<T>* SkewHeap<T>::clone(const SkewNode<T> *heap){
if(heap == NULL){
return NULL;
}
return new SkewNode<T>(heap -> element, clone(heap -> left), clone(heap -> right));
}
#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};
SkewHeap<int> *h1 = new SkewHeap<int>();
SkewHeap<int> *h2 = new SkewHeap<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 !