堆又叫二叉堆,是一种常用的数据结构。在实现中,有最大堆和最小堆两种。最小堆常常用于优先队列,堆也可以用于排序。
以最小堆为例:
最小堆中,一个结点的值不大于它的孩子。
1
/ \
2 3
/ \ / \
4 5 6 7
/ \ /
8 9 10
可以用数组实现堆得结构
图中位置为:0 1 2 3 4 5 6 7 8 9
可以看出父结点、左孩子、右孩子关系如下:
leftchild(i)=2*i+1
rightchild(i)=2*i+2
parent(i)=(i-1)/2;
向堆中添加一个元素时,添加到末尾;这时候可能破坏了堆得性质,因此要维护堆。添加在末尾,只要向上维护即可。
判断添加后是否满足堆的性质,不满足则维护这个结点。判断其父结点和父结点的左右两个孩子结点,最小的作为父结点。
之后再判断父结点是否满足堆得性质,不满足再向上维护。
从堆中删除结点时,要从堆顶删除。因为这个值是最值(最小堆的话就是最小值),之后把这个末尾结点放到堆顶。这样就破坏了堆
以最小堆为例:
最小堆中,一个结点的值不大于它的孩子。
1
/ \
2 3
/ \ / \
4 5 6 7
/ \ /
8 9 10
可以用数组实现堆得结构
图中位置为:0 1 2 3 4 5 6 7 8 9
可以看出父结点、左孩子、右孩子关系如下:
leftchild(i)=2*i+1
rightchild(i)=2*i+2
parent(i)=(i-1)/2;
向堆中添加一个元素时,添加到末尾;这时候可能破坏了堆得性质,因此要维护堆。添加在末尾,只要向上维护即可。
判断添加后是否满足堆的性质,不满足则维护这个结点。判断其父结点和父结点的左右两个孩子结点,最小的作为父结点。
之后再判断父结点是否满足堆得性质,不满足再向上维护。
从堆中删除结点时,要从堆顶删除。因为这个值是最值(最小堆的话就是最小值),之后把这个末尾结点放到堆顶。这样就破坏了堆
的性质,向下维护堆,直到叶子结点。
堆排序时,以升序为例,可以用最小堆,每次取出堆顶元素(最小值),放到另外一个地方存储,这对内存要求为O(2N)。
也可以用最大堆,把堆顶元素(最大值)依次放到存储堆得(数组或vector)的最后一个位置,堆得大小相应的减一。
#include<iostream>
#include<vector>
using namespace std;
class Heap{
public:
Heap():_size(0){}
void insert(int n);//插入
int delMin();//删除最小结点
vector<int> v;
private:
unsigned int left(int i){return 2*i+1;}//找到左孩子
unsigned int right(int i){return 2*i+2;}//找到右孩子
unsigned int parent(int i){return (i-1)/2;}//找到父节点
void up(int i);//向上为维护堆
void down(int i);
unsigned int _size;
};
void Heap::up(int i)
{
if(i==0)
return ;
unsigned int p=parent(i);//找到父节点
if(right(p)<v.size()) //p有有孩子
{
if(v[left(p)]>v[right(p)])//右孩子小于左孩子
{
//交换这两个结点
int tmp=v[right(p)];
v[right(p)]=v[p] ;
v[p]=tmp;
}
else{
int tmp=v[left(p)];
v[left(p)]=v[p];
v[p]=tmp;
}
}
else
{
int tmp=v[left(p)];
v[left(p)]=v[p];
v[p]=tmp;
}
if(v[p]<v[parent(p)])
up(p);
}
void Heap::down(int i)
{
//向下维护堆
unsigned int l=left(i);
unsigned int r=right(i);
unsigned int minNode; //数值最小的结点
if(l>=v.size())//左孩子超出范围
return ;
if(r>=v.size()) //右孩子超出范围,只有左孩子
{
if(v[l]<v[i])//左孩子子小于父结点
minNode=l;
else return;
}
else//既有左孩子又有右孩子
{
if(v[l]<v[r])//左孩子更小
minNode=l;
else minNode=r;
}
if(v[i]<v[minNode])// 不用再向下维护堆
return ;
int tmp=v[minNode];
v[minNode]=v[i];
v[i]=tmp;
down(minNode);
}
void Heap::insert(int n)//插入一个元素到末尾
{
v.push_back(n);//最后一个位置插入
unsigned int position=v.size()-1;//插入的这个数的位置
if(v[position]<v[parent(position)]) //改变了堆得性质,要维护
up(position);
}
int Heap::delMin()
{
if(v.empty())//空的
//异常
return 0;
int tmp=v[0];
v[0]=v[v.size()-1];
v.pop_back();
down(0);
return tmp;
}
int main()
{
Heap H;
for(int i=0;i<10;i++)
{
int k=rand()%100;
H.insert(k);
cout<<k<<" ";
}
cout<<endl;
while(!H.v.empty())//无存储排序元素,直接输出
cout<<H.delMin()<<" ";
return 0;
}