先上測試:
#include<iostream>
#include<vector>
#include<queue>
#include<random>
#include<fstream>
#include"max_heap.h"
#include"boost/progress.hpp"
using namespace std;
fstream output("log.log" , fstream::out);
//生成1000個隨機數,插入,
void test1(){
boost::progress_timer t; //計算時間
default_random_engine e;//生成隨機數
max_heap<int> m;
for(int i = 0; i != 10000 ; ++i)
m.push (e());
//打印頂點的值,彈出頂點,循環直到空爲止.
while(!m.empty ()){
output << m.top () << endl;//輸出到文件,查看文件發現輸出全部正確
m.pop ();
}
cout << "max_heap:";
}
//std::priority_queue,與自己的實現性能對比
void test2(){
boost::progress_timer t;
default_random_engine e;
priority_queue<int> q;
for(int i = 0; i != 10000 ; ++i)
q.push (e());
while(!q.empty ()){
output << q.top () << endl;
q.pop ();
}
cout << "std::priority_queue:";
}
int main()
{
test1();
output << "\n========================\n";
test2 ();
}
結果:
windows\linux:
由於使用了隨機數,所以多測了幾次,結果基本一致.居然比windows的實現快這麼多,我不敢相信我的眼晴.於是去Linux下測試了一下,同一個代碼,windows的居然差這麼多.
結論:1.這次實現還是比較好的.2.windows的實現真的有傳說中的那麼差?
再測試一下使用string的性能(實現的大部份操作是通過簡單的傳值而不是引用),所以有必要測試一下傳值的性能.
void test1(){
boost::progress_timer t;
uniform_int_distribution<int> u(0,26);
default_random_engine e;
max_heap<string> m;
for(int i = 0; i != 10000 ; ++i){
char buf[] = " ";
buf[0] = 'a' + u(e);
m.push (buf);
}
while(!m.empty ()){
output << m.top () << endl;
m.pop ();
}
cout << "max_heap:";
}
再上結果:
windows居然用了5秒,果然跟傳聞一樣,另外看來我的實現還是不錯的,
頭文件:
#ifndef MAX_HEAP_H
#define MAX_HEAP_H
#include<vector>
template<typename T>
class max_heap
{
public:
max_heap();
T& top();
void pop();
void push(const T item);
bool empty ();
int size();
private:
std::vector<T> vector_; //用vector實現
int left(int pos); //返回左兒子的索引
int right(int pos); //右兒子索引
int parent(int pos); //父親索引
bool isleaf(int pos); //判斷是否爲葉結點
void heapify(int pos); //使pos結點保持最大堆性質
void build_heap(); //建堆
};
#include"max_heap.cpp" //分離模版
#endif // MAX_HEAP_H
實現部分:
#ifndef HEAPCPP
#define HEAPCPP
#include"max_heap.h"
template<typename T>
max_heap<T>::max_heap(){ //默認構造函數
}
template<typename T>
bool max_heap<T>::empty (){
return vector_.empty ();
}
template<typename T>
T& max_heap<T>::top(){
return vector_.front ();
}
template<typename T>
int max_heap<T>::left(int pos){
return 2*pos +1;
}
template<typename T>
int max_heap<T>::right (int pos){
return 2*pos + 2;
}
template<typename T>
int max_heap<T>::parent (int pos){
return (pos-1)/2;
}
template<typename T>
int max_heap<T>::size(){
return vector_.size (); //元素個數
}
template<typename T>
bool max_heap<T>::isleaf(int pos){
int n = size();
return (n/2 <= pos) && (pos <= n-1); //元素位於最底一層,並不能大於size-1,則爲葉結點
}
template<typename T>
void max_heap<T>::heapify (int pos){
if (isleaf (pos))
return; //葉結點,跳出
int largestpos = pos; // 最大的索引
int left_pos = left(pos); //左索引
int right_pos = right(pos); //右索引
//1.兒子的索引不能超過size - 1, 找出比較大的元素在哪裏
if (left_pos <= size()-1 && vector_[left_pos] > vector_[largestpos])
largestpos = left_pos;
if (right_pos <= size()-1 && vector_[right_pos] > vector_[largestpos])
largestpos = right_pos;
//如果比較大的元素不是本結點,則要交換本結點的最大元素結點的值,對被交換的結點遞歸
if (largestpos != pos){
auto temp = vector_[pos];
vector_[pos] = vector_[largestpos];
vector_[largestpos] = temp;
heapify (largestpos);
}
}
//建堆,從倒數第二層開始,往根結點推進
template<typename T>
void max_heap<T>::build_heap (){
for (int pos = (size()-1)/2 ; pos >= 0 ; --pos)
heapify (pos);
}
template<typename T>
void max_heap<T>::pop(){
if (size() == 0) //沒有元素,拋出異常
throw std::runtime_error("out of range");
//把最後一個元素調至第一位,刪除最後一個元素,調用heapify使堆保持性質.
vector_[0] = vector_[size() -1];
vector_.pop_back ();
heapify (0);
}
//在尾部插入值,然後迭代上升,找到適合的位置.
template<typename T>
void max_heap<T>::push (const T item){
vector_.push_back (item);
int currpos = size()-1;
int parentops = parent (currpos);
while (vector_[parentops] < vector_[currpos]){
auto temp = vector_[currpos];
vector_[currpos] = vector_[parentops];
vector_[parentops] = temp;
currpos = parentops;
parentops = parent (currpos);
if (currpos == 0) //到頂部,結束
break;
}
}
#endif
實現沒什麼好說的.標準的二叉堆,另個,在頭文件的尾部加一句#include"max_heap.cpp",能使模版的實現的定義分離