heap.h
#ifndef _LEFTISTHEAP_H#define _LEFTISTHEAP_Husing namespace std;//虛基類class baseHeap {public:virtual void insert(int x) = 0;};//普通最小堆class heap:public baseHeap {public:int size;int *a; //儲存資料heap(int n=10000); //建構函式void merge(const heap &h); //與現有堆合并void insert(int x); //插入};//左式堆class leftistHeap:public baseHeap {struct leftistHeapNode { //結點int element; //元素leftistHeapNode *left; //左孩子leftistHeapNode *right; //右孩子int npl; //零路徑長leftistHeapNode(int x); //建構函式};public:leftistHeapNode *root; //根節點leftistHeap(leftistHeapNode *root = nullptr); //建構函式static leftistHeapNode* Merge(leftistHeapNode* h1, leftistHeapNode* h2);//合并(實現函數)void merge(const leftistHeap &h);//與現有堆合并(介面函數)void insert(int x); //插入};//斜堆class skewHeap:public baseHeap{struct skewHeapNode { //結點int element; //元素skewHeapNode *left; //左孩子skewHeapNode *right; //右孩子skewHeapNode(int x); //建構函式};public:skewHeapNode *root; //根節點skewHeap(skewHeapNode* root = nullptr); //建構函式static skewHeapNode* Merge(skewHeapNode* h1, skewHeapNode* h2); //合并(實現函數)void merge(const skewHeap &h);//與現有堆合并(介面函數)void insert(int x); //插入};//全域合并函數const skewHeap &merge(const skewHeap &h1, const skewHeap &h2); const leftistHeap &merge(const leftistHeap &h1, const leftistHeap &h2); const heap &merge(const heap &h1, const heap &h2); void print(heap h);//列印堆(用於測試)#endif
tmplate.h
#ifndef _TEMPLATE_H#define _TEMPLATE_H#include"heap.h"#include<queue>#include<iostream>// 列印堆(左式堆,斜堆) 用於測試// 層序遍曆,按層輸出template<typename T>void print(T root){if (!root)return;int cur = 1;int curnum = 1;int nextnum = 0;queue<T>q; //隊列q.push(root);while (!q.empty()) { //非空時curnum--;T tmp = q.front(); //當前隊頭元素出隊列cout << tmp->element << " ";q.pop();if (tmp->left) {q.push(tmp->left); //左孩子入隊列nextnum++;}if (tmp->right) {q.push(tmp->right); //右孩子入隊列nextnum++;}if (curnum == 0) { //控制按層輸出cout << endl;cur++;curnum = nextnum;nextnum = 0;}}cout << endl;}//交換孩子template<typename T>void swapChild(T &h){T tmp;tmp = h->right;h->right = h->left;h->left = tmp;}#endif
heap.cpp
#include"heap.h"#include<queue>#include<cstdlib>#include<climits>#include<iostream>using namespace std;heap::heap(int n) :size(0) {a = (int*)malloc(sizeof(int)*(n+1));a[0] = INT_MIN;if (!a)printf("error\n");}//初始化大小為0,哨兵為最小值void heap::merge(const heap &h){int i;//直接將外部堆插入for (i = 1; i != size; i++) {insert(h.a[i]);}}const heap& merge(const heap &h1, const heap &h2){int i;heap *tmp = new heap(h1.size+h2.size);//建立一個堆for (i = 1; i <= h1.size; i++) { //插入第一個堆tmp->insert(h1.a[i]);}for (i = 1; i <= h2.size; i++) { //插入第二個堆tmp->insert(h2.a[i]);}return *tmp; //返回建立堆}void heap::insert(int x){int p = ++size; //大小加1a[p] = x; //插入int tmp = a[p];for (; a[p / 2]>tmp; p /= 2) { //調整位置a[p] = a[p / 2];}a[p] = tmp;}void print(heap h){int i;for (i = 1; i < h.size; i++) { //遍曆輸出cout << h.a[i] << " ";}cout << endl;}
letist heap.cpp
#include"heap.h"#include"template.h"using namespace std;leftistHeap::leftistHeap(leftistHeapNode *root):root(root) { }leftistHeap::leftistHeapNode::leftistHeapNode(int x){element = x; //賦值left = right = nullptr; //左右孩子設為空白npl = 0; //零路徑長初始化為0}leftistHeap::leftistHeapNode* leftistHeap::Merge(leftistHeapNode* h1, leftistHeapNode* h2){if (!h1) return h2; //h1為空白,返回h2if (!h2) return h1; //h2為空白,返回h1if (h1->element > h2->element) { //維護h1的元素始終小於h2leftistHeapNode* tmp = h2;h2 = h1;h1 = tmp;}if (!h1->left)h1->left = h2; //如果h1沒有左孩子,讓h2成為h1的左孩子else { //如果h1有左孩子h1->right = Merge(h1->right, h2); //合并h1的右孩子和h2if (h1->left->npl<h1->right->npl)swapChild(h1); //如果左式堆性質被破壞,即左孩子的零路徑長小於右孩子,交換左右孩子h1->npl = h1->right->npl + 1; //更新h1的零路徑長}return h1;}const leftistHeap &merge(const leftistHeap &h1, const leftistHeap &h2){//將傳回值leftistHeapNode轉換成leftistHeap,實現標準化介面leftistHeap *ans=new leftistHeap(leftistHeap::Merge(h1.root, h2.root));return *ans;}void leftistHeap::merge(const leftistHeap &h){//調用已有mergeroot = Merge(root, h.root);}void leftistHeap::insert(int x){if (!root) { //不存在根節點,建立root = new leftistHeapNode(x);}else { //否則,將新節點和原堆合并leftistHeapNode *tmp = new leftistHeapNode(x);root = Merge(root, tmp);}}
skewheap.cpp
#include"heap.h"#include"template.h"using namespace std;skewHeap::skewHeap(skewHeapNode* root):root(root) { }skewHeap::skewHeapNode::skewHeapNode(int x){element = x; //賦值left = right = nullptr; //左右孩子都為空白}skewHeap::skewHeapNode* skewHeap::Merge(skewHeapNode* h1, skewHeapNode* h2){if (!h1) return h2; //h1為空白,返回h2if (!h2) return h1; //h2為空白,返回h1if (h1->element > h2->element) { //維護h1的元素始終小於h2skewHeapNode* tmp = h2;h2 = h1;h1 = tmp;}if (!h1->left)h1->left = h2; //如果h1沒有左孩子,讓h2成為h1的左孩子else {h1->right = Merge(h1->right, h2); //合并h1的右孩子和h2swapChild(h1); //交換孩子}return h1;}const skewHeap &merge(const skewHeap &h1, const skewHeap &h2){//將傳回值skewHeapNode轉換成skewHeap,實現標準化介面skewHeap* ans = new skewHeap(skewHeap::Merge(h1.root, h2.root));return *ans;}void skewHeap::merge(const skewHeap &h) {//調用已有mergeroot = Merge(root, h.root);}void skewHeap::insert(int x){if (!root) {root = new skewHeapNode(x);//不存在根節點,建立}else { //否則,將新節點和原堆合并skewHeapNode *tmp = new skewHeapNode(x);root = Merge(root,tmp);}}
main.cpp
#include"heap.h"#include"template.h"#include<algorithm>#include<cstdio>#include<chrono>using namespace std;int main(){ srand(unsigned(time(nullptr)));int n = 10000;int i;int count = 0;double sum1=0, sum2=0, sum3=0;//統計三個時間chrono::time_point<chrono::high_resolution_clock> start,end;//開始,結束chrono::duration<double> seconds;//計時while (n) { //n為測試資料大小count++;if (count == 100) { //計算100次後輸出printf("%d:\n%lf,%lf,%lf\n",n, sum1 , sum2 , sum3 );count = 0;n -= 1000; //測試資料減少1000sum1 = 0.0, sum2 = 0.0, sum3 = 0.0; //更新sum為0}leftistHeap h1, h2, h3;skewHeap h4, h5, h6;heap h7(n), h8(n), h9(n);int a[10002];for (i = 0; i < n; i++) {a[i] = 2 * i;}random_shuffle(a, a + n); //產生資料(偶數)for (int i = 0; i < n; i++) { //產生第一棵樹h1.insert(a[i]);h4.insert(a[i]);h7.insert(a[i]);}for (i = 0; i < n; i++) {a[i] = 2 * i + 1;}random_shuffle(a, a + n); //產生資料(奇數)for (int i = 0; i < n; i++) { //產生第二棵樹h2.insert(a[i]);h5.insert(a[i]);h8.insert(a[i]);}//計算leftistHeap start = chrono::high_resolution_clock::now();h3 = merge(h1, h2);end = chrono::high_resolution_clock::now();seconds = end - start;sum1 = sum1 + seconds.count();//計算skewHeapstart = chrono::high_resolution_clock::now();h6 = merge(h4, h5);end = chrono::high_resolution_clock::now();seconds = end - start;sum2 = sum2 + seconds.count();//計算heapstart = chrono::high_resolution_clock::now();h9 = merge(h7, h8);end = chrono::high_resolution_clock::now();seconds = end - start;sum3 = sum3 + seconds.count();}system("pause");}