/**收获及心得
1.熟悉了二叉堆的class,并将其改为了升级版的最大-最小二叉堆
2.学会了声明,定义以及使用友元
3.对vector有了更深的理解
4.percolate down函数的算法断断续续写了四五天才大概满足次二叉堆的性质,收获蛮多
5.至于本次程序是为完成书上P187 6.18的练习题
***遗留下的问题
1.merge函数还未完成,主要还未了解merge过程
2.本想尝试写一个抛出异常的类来解决,堆为空的情况,最后一exit代替
3.关于屏幕上的移动光标的问题,本想直接生成一个树的形状,曾考虑用数组来实现,
不过感觉其意义不大,有空试试能否直接移动光标来实现
4.总感觉percolate down函数写的有点拖沓,不如书上二叉堆的来的简洁
5.22~5.29
*/
第一部分 老样子 最大最小堆的类
#ifndef BINARYHEAP_H
#define BINARYHEAP_H
#include<vector>
#include<iostream>
using namespace std;
class BinaryHeap
{
public:
BinaryHeap();
virtual ~BinaryHeap();
BinaryHeap(const vector<int> &items);
const int &findMin() const;
const int &findMax() const;
void insert(const int &x);
void deleteMin();
void deleteMin(int &minItem);
void deleteMax();
void deleteMax(int &maxItem);
void print() const;
private:
int current_size;
vector<int> array;
void build_heap();
void percolateDown(int hole);
bool isEmpty() const;
void makeEmpty();
friend int findMax_grandson(BinaryHeap&H,int hole);
friend int findMin_grandson(BinaryHeap&H,int hole);
};
#endif // BINARYHEAP_H
第二部分为上头文件相关函数的具体定义
#include "..\include\BinaryHeap.h"
#include<cmath>
#include<cstdlib>
#include<iostream>
using namespace std;
BinaryHeap::BinaryHeap()//default constructor
{
array.resize(100);
current_size=0;
}
BinaryHeap::~BinaryHeap()
{
makeEmpty();
}
BinaryHeap::BinaryHeap(const vector<int>&items)//copy constructor
:array(items.size()+10),current_size(items.size())
{
for(unsigned i=0;i<items.size();i++)
array[i+1]=items[i];
build_heap();
}
void BinaryHeap::insert(const int &x)
{
if(current_size==array.size()-1)
array.resize(array.size()*2);
int hole=++current_size;
int depth=log(hole)/log(2);
while(depth>1)
{
if(depth/2==0)//percolate up in even depth
{
if(x<array[hole/2]&&x<array[hole/4])
{
array[hole]=array[hole/4];
hole=hole/4;
depth-=2;
}
else if(x>array[hole/2]&&x>array[hole/4])
{
array[hole]=array[hole/2];
hole=hole/2;
depth-=1;
}
else return;//the hole is at the right position,accord with the rule of min_max binaryheap
}
else//percolate up in odd depth
{
if(x>array[hole/2]&&x>array[hole/4])
{
array[hole]=array[hole/4];
hole=hole/4;
depth-=2;
}
else if(x<array[hole/2]&&x<array[hole/4])
{
array[hole]=array[hole/2];
hole=hole/2;
depth-=1;
}
else return;//the same as above
}
}
if(depth==1&&array[hole/2]>x)//only two storeys
{
array[hole]=array[hole/2];
hole=hole/2;
}
array[hole]=x;
}
void BinaryHeap::print() const//print this heap
{
cout<<"**************************************************"<<endl;
for(int i=1;i<=current_size;i++)
cout<<array[i]<<" ";
cout<<endl;
}
void BinaryHeap::deleteMin()
{
if(isEmpty())
{
cerr<<"Error!!This heap is empty!"<<endl;
exit(1);//if having time,making a throw exception
}
array[1]=array[current_size--];
percolateDown(1);
}
void BinaryHeap::deleteMin(int &minItem)
{
if(isEmpty())
{
cerr<<"Error!!This heap is empty!"<<endl;
exit(1);
}
minItem=array[1];//using minItem to record the minimum
array[1]=array[current_size--];
percolateDown(1);
}
void BinaryHeap::deleteMax()
{
if(isEmpty())
{
cerr<<"Error!!This heap is empty!!"<<endl;
exit(1);
}
else if(current_size==1) current_size--;
else if(current_size==2) current_size--;
else
{
if(array[3]>array[2])
{
array[3]=array[current_size--];
percolateDown(3);
}
else
{
array[2]=array[current_size--];
percolateDown(2);
}
}
}
void BinaryHeap::deleteMax(int &maxItem)
{
if(isEmpty())
{
cerr<<"Error!!This heap is empty!!"<<endl;
exit(1);
}
//using maxItem to record the maximum
else if(current_size==1) {maxItem=array[1];current_size--;}
else if(current_size==2) {maxItem=array[2];current_size--;}
else
{
if(array[3]>array[2])
{
maxItem=array[3];
array[3]=array[current_size--];
percolateDown(3);
}
else
{
maxItem=array[2];
array[2]=array[current_size--];
percolateDown(2);
}
}
}
bool BinaryHeap::isEmpty() const
{
if(current_size==0)
return true;
return false;
}
const int& BinaryHeap::findMin() const
{
if(isEmpty())
{
cerr<<"Error!! this binaryheap is empty!!"<<endl;
exit(1);
}
return array[1];
}
const int& BinaryHeap::findMax() const//find the maximum
{
if(isEmpty())
{
cerr<<"Error!!This binaryheap is empty!!"<<endl;
exit(1);
}
else if(current_size==1)
return array[1];
else if(current_size==2)
return array[2];
else
{
if(array[2]<array[3])
return array[3];
return array[2];
}
}
void BinaryHeap::makeEmpty()
{
array.clear();//clear the array
current_size=0;
}
void BinaryHeap::percolateDown(int hole)//the most importment algorithm of this binaryheap
{
int now_depth=log(hole)/log(2);
int depth=log(current_size)/log(2);
int child;
int grandson;
int tmp=array[hole];
if(now_depth%2==1)//when at odd depth,percolate down
{
while(depth-now_depth>=2)
{
child=2*hole;
if(array[child+1]>array[child]) child++;
if(current_size>=4*hole)
grandson=findMax_grandson(*this,hole);
else break;//having no grandson,but maybe depth-now_depth=2
//if do nothing at the two judgements below,the hole is in the right position
if(tmp>=array[child]&&tmp>=array[grandson]) return;
if(tmp<array[child])//pay attention to the value of hole,it does not change!!
{
array[hole]=array[child];
array[child]=tmp;
tmp=array[hole];
}
if(tmp<array[grandson])//change the hole at this point
{
array[hole]=array[grandson];
array[grandson]=tmp;
hole=grandson;
tmp=array[hole];
}
else {hole=grandson; tmp=array[hole];}
now_depth+=2;//percolate down 2 depths
}
if(depth-now_depth==2)//end the loop from the break above
{
child=2*hole;
if(array[child+1]>array[child]) child++;
if(array[hole]<array[child])
{
tmp=array[hole];
array[hole]=array[child];
array[child]=tmp;
}
}
if(depth-now_depth==1)//only 2 storeys
{
child=2*hole;
if(current_size>child&&array[child+1]>array[child]) child++;
if(child<=current_size&&array[child]>array[tmp])//exchange hole with the bigger child
{
tmp=array[hole];
array[hole]=array[child];
array[child]=tmp;
}
}
}
else//when the hole at even depth
{
while(depth-now_depth>=2)
{
tmp=array[hole];
child=2*hole;
if(array[child+1]<array[child]) child++;
if(current_size>=4*hole)
grandson=findMin_grandson(*this,hole);
else break;
//if do nothing at the two judgements below,the hole is in the right position
if(tmp<=array[grandson]&&tmp<=array[child]) return;
if(tmp>array[child])//pay attention to the hole,the same as above
{
array[hole]=array[child];
array[child]=tmp;
tmp=array[hole];
}
if(tmp>array[grandson])
{
array[hole]=array[grandson];
array[grandson]=tmp;
hole=grandson;
tmp=array[hole];
}
else {hole=grandson; tmp=array[hole];}
now_depth+=2;//percolatedown 2 depths
}
if(depth-now_depth==2)//end the loop from the break above
{
child=2*hole;
if(array[child+1]>array[child]) child++;
if(array[hole]>array[child])
{
tmp=array[hole];
array[hole]=array[child];
array[child]=tmp;
}
}
if(depth-now_depth==1)
{
child=2*hole;
if(current_size>child&&array[child+1]<array[child]) child++;
if(child<=current_size&&array[child]<array[hole])
{ tmp=array[hole];
array[hole]=array[child];
array[child]=tmp;
}
}
}
}
void BinaryHeap::build_heap()
{
for(int i=current_size/2;i>0;i--)
percolateDown(i);
}
//the declaration of the friend functions
int findMin_grandson(BinaryHeap&H,int hole)//finding the position of minimal grandson
{
int grandson=4*hole;
if(grandson==H.current_size) ;
else if(grandson+1==H.current_size)
{
if(H.array[H.current_size]<H.array[grandson]) grandson++;
else ;
}
else if(grandson+2==H.current_size)
{
for(int i=grandson;i<4*hole+3;i++)
{
grandson=H.array[grandson]<H.array[i]?grandson:i;
}
}
else
{
for(int i=grandson;i<4*hole+4;i++)
grandson=H.array[grandson]<H.array[i]?grandson:i;
}
return grandson;
}
int findMax_grandson(BinaryHeap&H,int hole)//finding the position of maximal grandson
{
int grandson=4*hole;
if(grandson==H.current_size) ;
else if(grandson+1==H.current_size)
{
if(H.array[H.current_size]>H.array[grandson]) grandson++;
else ;
}
else if(grandson+2==H.current_size)
{
for(int i=grandson;i<4*hole+3;i++)
{
grandson=H.array[grandson]>H.array[i]?grandson:i;
}
}
else
{
for(int i=grandson;i<4*hole+4;i++)
grandson=H.array[grandson]>H.array[i]?grandson:i;
}
return grandson;
}
第三部分 为类的测试
#include <iostream>
#include"include/BinaryHeap.h"
using namespace std;
int main()//symble checking
{
vector<int>aa;
for(int i=12;i>0;i--)
aa.push_back(i);
BinaryHeap H(aa);
H.print();
H.deleteMax();
H.print();
H.insert(16);
H.print();
cout<<H.findMax()<<endl;
}