什么是大小堆?
大小堆是基于完全二叉树的结构;
大堆:任意一个结点的左右孩子的数据都小于此结点的数据,位于堆顶的结点的数据最大。
小堆:任意一个结点的左右孩子的数据都大于此结点的数据,位于堆顶的结点的数据最小。
下面以小堆为例,图解:
以下都是以小堆为例
如何创建小堆?
首先我们只会得到一个数组,并且我们知道堆最终形态是完全二叉树。通过递归的思想,如果能把最后一个以非叶子结点为根的树变为小堆,然后改变倒数第二个以非叶子结点为根的树,以此类推就可以将整个树变为小堆。函数内需要用到向下调整法可看注释:
void AdjustDown(pHeapStack pHs,int root) //向下调整法,以phs为根节点的整棵树变为大小堆
{
int parent = root;
int child = (root<<1)+1;
assert(pHs);
while(child<pHs->sz)
{
if(child+1<pHs->sz && pHs->_compare(pHs->data[child+1],pHs->data[child]))
child = child+1; //谁跟顶层的换值,下一步就调整谁,因为换了的就有可能不符合小堆
if(pHs->_compare(pHs->data[child],pHs->data[parent]))
Swap(&pHs->data[child],&pHs->data[parent]);
parent = child; //先把顶层的调整好再去调整后面的
child = (child<<1)+1;
}
}
void CreatHeapStack(pHeapStack pHs,Heap_DT* array,int ArrSz,PCompare compare)
{
int root;
assert(array);
pHs->data = (Heap_DT*)malloc(sizeof(Heap_DT)*ArrSz);
pHs->_compare = compare;
if(NULL == pHs->data)
{
assert(0);
return;
}
memcpy(pHs->data,array,ArrSz*sizeof(Heap_DT));
pHs->sz = ArrSz;
pHs->dilatation = ArrSz;
for(root=((pHs->sz-1-1)>>1) ;root>=0 ;root--) //得到最后一个非叶子节点的下标,进行循环
AdjustDown(pHs,root);
}
小堆的增加元素操作
直接往原堆数组的最后添加一个元素,然后通过向上调整的方式。对新加的元素,它到根节点这条路上的所有树都调整符合小堆的特性就好。
void AdjustUp(pHeapStack pHs,int root)
{
int child = root;
int parent = ((root-1)>>1);
assert(pHs);
while(parent>=0)
{
if(pHs->_compare(pHs->data[child],pHs->data[parent]))
Swap(&pHs->data[parent],&pHs->data[child]);
child = parent; //向上调整,孩子变父亲,
parent = ((parent-1)>>1); //双亲变新的双亲
}
}
void InsertHeap(pHeapStack pHs,Heap_DT d)
{
assert(pHs);
IsFull(pHs);
pHs->data[pHs->sz++] = d;
AdjustUp(pHs,pHs->sz-1);
}
小堆的删除元素操作
将要删除的元素与堆数组最后一个元素的值交换,然后堆数组数量减一,现在已经删除了要删除的元素,但是因为交换了元素值,小堆的性质被破坏。用向下调整的方法,从原本交换的结点位置开始,将以它为根的树变为小堆。
void AdjustDown(pHeapStack pHs,int root)
{
int parent = root;
int child = (root<<1)+1;
assert(pHs);
while(child<pHs->sz)
{
if(child+1<pHs->sz && pHs->_compare(pHs->data[child+1],pHs->data[child]))
child = child+1;
if(pHs->_compare(pHs->data[child],pHs->data[parent]))
Swap(&pHs->data[child],&pHs->data[parent]);
parent = child;
child = (child<<1)+1;
}
}
void RemoveHeap(pHeapStack pHs)
{
assert(pHs);
Swap(&pHs->data[0],&pHs->data[pHs->sz-1]); //交换
pHs->sz--; //删除
AdjustDown(pHs,0); //向下调整将改变之后的树变为小堆
}