#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;
}