#ifndef DHEAP_H_INCLUDED
#define DHEAP_H_INCLUDED
#include<vector>
#include<limits>
//#include<functional>
//#define DEBUG
// 一些辅助工具
namespace heap_aux{
const int MAX_SIZE = std::numeric_limits<int>::max()-1;
template<typename T> inline void swap(T& a, T& b){
T tmp = a;
a = b;
b = tmp;
}
template<typename T>struct equal_to{
bool operator()(const T& a, const T& b) const { return a == b ? true : false; }
};
template<typename T>struct not_equal_to{
bool operator()(const T& a, const T& b) const { return a != b ? true : false; }
};
template<typename T>struct less{
bool operator()(const T& a, const T& b) const { return a < b ? true : false; }
};
template<typename T>struct greater{
bool operator()(const T& a, const T& b) const { return a > b ? true : false; }
};
template<typename T>struct less_equal{
bool operator()(const T& a, const T& b) const { return a <= b ? true : false; }
};
template<typename T>struct greater_equal{
bool operator()(const T& a, const T& b) const { return a >= b ? true : false; }
};
// 异常处理信息类
struct heap_error{
std::string error_info;
heap_error(std::string _error_info) :error_info(_error_info) {}
};
}
template<typename T, typename Compare = heap_aux::greater_equal<T> >
class dheap{
public: // contructors
dheap(int _d = 2, const Compare& _comp = Compare()) : coll(0), d(_d), heapsize(0), comp(_comp){}
dheap(size_t size, int _d = 2, const Compare& _comp = Compare()) : coll(size, 0), d(_d), heapsize(0), comp(_comp) {}
dheap(std::vector<T> _coll, int _d = 2, const Compare& _comp = Compare()) : coll(_coll), d(_d), heapsize(_coll.size()), comp(_comp) {
make_heap();
}
~dheap(){}
public: // access functions
inline const int get_heapsize() const { return heapsize;}
inline const T& getTop() const{
if(!heapsize){ //能在函数内解决,就不使用异常了
std::cerr<<"heap is empty/n";
return T();//这个处理其实不很优雅,我也不知道该怎么处理更好
}
return *coll.begin();
}
inline const T& get_elem(int index) const{ return coll[index];}
public: // operations
void insert(T item){
int index = heapsize; // 初始时当然就是插入到数组尾部了
if(index == heap_aux::MAX_SIZE){
std::cerr<<"heap is full./n";
return;
}
coll.push_back(item);
++heapsize;
try{
heapify(index, heapsize-1);
}
catch(heap_aux::heap_error& he){
std::cerr<<he.error_info;
return;
}
}
void delete_heap(int index = 0){ // 默认删除堆顶元素
if(index == 0) heap_aux::swap(*coll.begin(), *(coll.end()-1));
else{
if(index > heapsize - 1){
std::cerr<<"index exceeded/n";
return;
}
heap_aux::swap(coll[index], *(coll.end()-1));
}
--heapsize;
try{
heapify(index, heapsize-1);
}
catch(heap_aux::heap_error& he){
std::cerr<<he.error_info;
return;
}
}
void modify_top(T dest){ //默认修改堆顶元素
if(coll.empty()){
std::cerr<<"heap is empty./n";
return;
}
T tmp = *coll.begin();
*coll.begin() = dest;
if(!comp(dest, tmp)){
try{
heapify(0, heapsize-1);
}
catch(heap_aux::heap_error& he){
std::cerr<<he.error_info;
return;
}
}
}
void merge(const dheap& other){
for(int i = 0; i < other.get_heapsize(); ++i)
coll.push_back(other.get_elem(i));
heapsize += other.get_heapsize();
make_heap();
}
private: // inner auxiliaies
inline void make_heap(){
for(int i = (heapsize-2)/d; i>=0; --i){ //注意heapsize要减2
try{
heapify(i, heapsize-1);
}
catch(heap_aux::heap_error& he){
std::cerr<<he.error_info;
return;
}
}
}
inline void heapify(int start, int len){
if(start > heapsize -1)
throw heap_aux::heap_error("index exceed./n");
int son = start*d+1; // 左子节点索引,因为下标从0开始
T item = coll[start];
while(son <= len){
if(son < len && (!comp(coll[son], coll[son+1])) )
++son;
if(comp(item, coll[son]) ) break; // (*)
coll[(son-1)/d] = coll[son]; //coll[son>>1]就是父节点,(*)行没有break出去,说明违反堆性质
son=son*d+1; //孙子节点
}
#ifdef DEBUG
std::cout<<"DEBUG:/t";
for(size_t i = 0; i < heapsize; ++i)
std::cout<<coll[i]<<' ';
std::cout<<"/n";
#endif
coll[(son-1)/d] = item;
}
private:
std::vector<T> coll;
int d;
int heapsize;
Compare comp;
};
#endif // DHEAP_H_INCLUDED
// 以下为Windows下测试文件,我实测的时候也对insert delete等操作做了测试,下面仅仅是建堆的测试,实际上要改为insert那也很简单
#include<iostream>
//#include<vector>
#include <windows.h>
#include"binaryheap.h"
#include"random.h" // 这个是个人写的随机数发生器,因为我觉得系统默认的随机数既慢且随机性能不好,您用系统提供的也是可以的啦~
#define CORRECTNESS_MODE
//#define TIME_MODE
#ifdef CORRECTNESS_MODE
#define E 4
#define SZ (1<<E)
#define C 5
#else // TIME_MODE
#define E 20
#define SZ (1<<E)
#define C 20
#endif
template<typename T> inline void print_vector(const std::vector<T>& vec){
std::cout<<"elements in vector:/n";
for(size_t i = 0; i<vec.size(); ++i)
std::cout<<vec[i]<<' ';
std::cout<<"/n";
}
template<typename T>inline void print_heap(const binaryheap<T>& bh){
std::cout<<"elements in binaryheap:/n";
for(int i = 0; i < bh.get_heapsize(); ++i)
std::cout<<bh.get_elem(i)<<' ';
std::cout<<"/n";
}
// 严格说这个正确性测试方法是错的,应该递归检查是否满足堆性质,由于我们的堆和STL的堆使用的算法一致,就偷懒了
template<typename T>inline void correntness_check(const binaryheap<T>& bh, const std::vector<T>& vec){
for(int i = 0; i < bh.get_heapsize(); ++i){
if( vec[i] != bh.get_elem(i) )
std::cout<<"binaryheap works ERROR!!/n";
}
std::cout<<"binaryheap works fine!";
}
int main()
{
std::vector<size_t> vnth(C), v1(SZ), v2; // v1为STL测试数据, v2为binaryheap测试数据 std::cout << "testing is in progress ..." << '/n';
Sleep(1000);
for(size_t i = 0; i < C; ++i)
{
for(size_t j = 0; j<SZ; ++j) v1[j] = irand();
v2 = v1;
std::cout<<"/n/nTest "<<i<<"/n";
#ifdef TIME_MODE
DWORD t1 = GetTickCount();
#endif
make_heap(v1.begin(), v1.end());
#ifdef CORRECTNESS_MODE
print_vector(v1);
#else //TIME_MODE
std::cout<<"STL make_heap() used "<<GetTickCount() - t1<<"ms/n";
#endif
#ifdef TIME_MODE
DWORD t2 = GetTickCount();
#endif
binaryheap<size_t> bh(v2);
#ifdef CORRECTNESS_MODE
print_heap(bh);
correntness_check(bh, v1);
#else //TIME_MODE
std::cout<<"binaryheap make heap used "<<GetTickCount() - t2<<"ms/n";
#endif
}
return 0;
}