介绍
二叉堆是完全二元树或者近似完全二元树,按照数据的排列方式可以分为两种:最大堆和最小堆。
- 最大堆:父节点的键值总是大于或等于任何一个子节点的键值。
- 最小堆:父节点的键值总是小于或等于任何一个子节点的键值。
实现原理
1、二叉堆一般使用数组实现,如果从索引1开始存放元素,那么
- i 的左孩子是2*i
- i 的右孩子是2*i+1
- i 的父节点 i/2
2、插入操作(最大堆)
当向最大堆中添加数据时,先将数据加入最大堆的最后(即数组中最后一个元素的下一个位置),然后尽可能把这个元素往上挪,直到挪不动为止。
3、删除操作(最大堆)
当从最大堆中删除数据时,先删除该数据,然后用最大堆中最后一个元素插入这个空位,然后把这个空位尽量向下挪,直到重新变为最大堆。
注意:最小堆相比最大堆的实现只需改动大小关系即可。
代码实现(C++)
最大堆
//最大堆
#include<iostream>
using namespace std;
template<class T>
class MaxHeap{
private:
T *heap;//数据
int capacity;//总的容量
int size;//实际容量
void down(int start,int end);//最大堆向下调整算法
void up(int start);//最大堆向上调整算法
public:
MaxHeap();
MaxHeap(int capacity);
~MaxHeap();
int getIndex(T data);//返回data在二叉堆中的索引
bool remove(T data);//删除最大堆中的data
bool insert(T data);//将data插入二叉堆中
void print();//打印二叉堆
};
//构造函数
template<class T>
MaxHeap<T>::MaxHeap(int capacity)
{
this->capacity=capacity;
this->size=0;
heap=new T[this->capacity];
}
template<class T>
MaxHeap<T>::MaxHeap()
{
new (this)MaxHeap(30);
}
//析构函数
template<class T>
MaxHeap<T>::~MaxHeap()
{
size=capacity=0;
delete[] heap;
}
//返回data在二叉堆的索引位置,如果不存返回-1
template<class T>
int MaxHeap<T>::getIndex(T data)
{
for(int i=1;i<=size;i++)
if(heap[i]==data)
return i;
return -1;
}
//最大堆的向上调整算法
template<class T>
void MaxHeap<T>::up(int start)//start上调的开始位置
{
int c=start;
T temp=heap[c];
int p=c/2;//p是c的父节点
while(p>0)
{
if(temp<=heap[p])
break;//上调结束
else
{
heap[c]=heap[p];
c=p;
p=p/2;
}
}
heap[c]=temp;
}
//插入值为data的元素
template<class T>
bool MaxHeap<T>::insert(T data)
{
if(size==capacity)//堆已满,添加失败,返回false
return false;
heap[++size]=data;//将数据插在最后
up(size);//上调元素
return true;
}
/*
最大堆的向下调整算法
start:被下调节点的起始位置
end:数组的最后一个元素的位置
*/
template<class T>
void MaxHeap<T>::down(int start,int end)
{
int c=start;//c表示当前结点的位置
T temp=heap[c];//当前结点的值
int l=2*c;//c的左孩子
//进行下调
while(l<=end)
{
// l是左孩子,l+1是右孩子
if(l<end&&heap[l]<heap[l+1])
l++;//左右两个孩子中选择较大者
if(temp>=heap[l])//下调结束
break;
else
{
heap[c]=heap[l];
c=l;
l=l*2;
}
}
heap[c]=temp;
}
//删除值为data的元素
template<class T>
bool MaxHeap<T>::remove(T data)
{
//获取data在数组中的索引
int index=getIndex(data);
if(index==-1)//未找到 ,删除失败,返回false
return false;
heap[index]=heap[size--];//用最后元素填补index位置
down(index,size);//从index位置开始自上而下调整为最大堆
return true;//删除失败
}
//打印二叉堆
template<class T>
void MaxHeap<T>::print()
{
if(size==0)
cout<<"堆为空!";
for(int i=1;i<=size;i++)
cout<<heap[i]<<" ";
cout<<endl;
}
int main()
{
MaxHeap<int> *tree=new MaxHeap<int>;
while(1)
{
cout<<"1.插入元素\n2.删除元素\n3.打印最大堆\n4.退出\n";
int op;
cin>>op;
if(op==1)
{
int e;
cout<<"输入元素值:";
cin>>e;
bool flag=tree->insert(e);
cout<<"---------------"<<endl;
cout<<"插入元素"<<e;
if(flag)
cout<<"成功!"<<endl;
else
cout<<"失败!"<<endl;
cout<<"---------------"<<endl;
}
else if(op==2)
{
int e;
cout<<"输入元素值:";
cin>>e;
bool flag=tree->remove(e);
cout<<"---------------"<<endl;
cout<<"删除元素"<<e;
if(flag)
cout<<"成功!"<<endl;
else
cout<<"失败!"<<endl;
cout<<"---------------"<<endl;
}
else if(op==3)
{
cout<<"---------------"<<endl;
tree->print();
cout<<"---------------"<<endl;
}
else
break;
}
return 0;
}
最小堆
//最大堆
#include<iostream>
using namespace std;
template<class T>
class MaxHeap{
private:
T *heap;//数据
int capacity;//总的容量
int size;//实际容量
void down(int start,int end);//最大堆向下调整算法
void up(int start);//最大堆向上调整算法
public:
MaxHeap();
MaxHeap(int capacity);
~MaxHeap();
int getIndex(T data);//返回data在二叉堆中的索引
bool remove(T data);//删除最大堆中的data
bool insert(T data);//将data插入二叉堆中
void print();//打印二叉堆
};
//构造函数
template<class T>
MaxHeap<T>::MaxHeap(int capacity)
{
this->capacity=capacity;
this->size=0;
heap=new T[this->capacity];
}
template<class T>
MaxHeap<T>::MaxHeap()
{
new (this)MaxHeap(30);
}
//析构函数
template<class T>
MaxHeap<T>::~MaxHeap()
{
size=capacity=0;
delete[] heap;
}
//返回data在二叉堆的索引位置,如果不存返回-1
template<class T>
int MaxHeap<T>::getIndex(T data)
{
for(int i=1;i<=size;i++)
if(heap[i]==data)
return i;
return -1;
}
//最小堆的向上调整算法
template<class T>
void MaxHeap<T>::up(int start)//start上调的开始位置
{
int c=start;
T temp=heap[c];
int p=c/2;//p是c的父节点
while(p>0)
{
if(temp>=heap[p])//最大堆是<=
break;//上调结束
else
{
heap[c]=heap[p];
c=p;
p=p/2;
}
}
heap[c]=temp;
}
//插入值为data的元素
template<class T>
bool MaxHeap<T>::insert(T data)
{
if(size==capacity)//堆已满,添加失败,返回false
return false;
heap[++size]=data;//将数据插在最后
up(size);//上调元素
return true;
}
/*
最小堆的向下调整算法
start:被下调节点的起始位置
end:数组的最后一个元素的位置
*/
template<class T>
void MaxHeap<T>::down(int start,int end)
{
int c=start;//c表示当前结点的位置
T temp=heap[c];//当前结点的值
int l=2*c;//c的左孩子
//进行下调
while(l<=end)
{
// l是左孩子,l+1是右孩子
if(l<end&&heap[l]>heap[l+1])//最大堆是heap[l]<heap[l+1]
l++;//左右两个孩子中选择较小者
if(temp<=heap[l])//下调结束
break;
else
{
heap[c]=heap[l];
c=l;
l=l*2;
}
}
heap[c]=temp;
}
//删除值为data的元素
template<class T>
bool MaxHeap<T>::remove(T data)
{
//获取data在数组中的索引
int index=getIndex(data);
if(index==-1)//未找到 ,删除失败,返回false
return false;
heap[index]=heap[size--];//用最后元素填补index位置
down(index,size);//从index位置开始自上而下调整为最大堆
return true;//删除失败
}
//打印二叉堆
template<class T>
void MaxHeap<T>::print()
{
if(size==0)
cout<<"堆为空!";
for(int i=1;i<=size;i++)
cout<<heap[i]<<" ";
cout<<endl;
}
int main()
{
MaxHeap<int> *tree=new MaxHeap<int>;
while(1)
{
cout<<"1.插入元素\n2.删除元素\n3.打印最小堆\n4.退出\n";
int op;
cin>>op;
if(op==1)
{
int e;
cout<<"输入元素值:";
cin>>e;
bool flag=tree->insert(e);
cout<<"---------------"<<endl;
cout<<"插入元素"<<e;
if(flag)
cout<<"成功!"<<endl;
else
cout<<"失败!"<<endl;
cout<<"---------------"<<endl;
}
else if(op==2)
{
int e;
cout<<"输入元素值:";
cin>>e;
bool flag=tree->remove(e);
cout<<"---------------"<<endl;
cout<<"删除元素"<<e;
if(flag)
cout<<"成功!"<<endl;
else
cout<<"失败!"<<endl;
cout<<"---------------"<<endl;
}
else if(op==3)
{
cout<<"---------------"<<endl;
tree->print();
cout<<"---------------"<<endl;
}
else
break;
}
return 0;
}