先上测试:
#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",能使模版的实现的定义分离