【数据结构】大小堆的理解,创建,增加和删除元素操作

本文介绍了大小堆的概念,基于完全二叉树的结构,大堆的堆顶元素最大,小堆的堆顶元素最小。详细讲解了小堆的创建过程,通过递归将数组转化为小堆。接着讨论了小堆中增加元素的操作,通过向上调整保持堆性质。最后阐述了小堆删除元素的步骤,包括与末尾元素交换、堆数组数量减少及向下调整恢复堆的特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么是大小堆?

大小堆是基于完全二叉树的结构;
大堆:任意一个结点的左右孩子的数据都小于此结点的数据,位于堆顶的结点的数据最大。
小堆:任意一个结点的左右孩子的数据都大于此结点的数据,位于堆顶的结点的数据最小。
下面以小堆为例,图解:

在这里插入图片描述

以下都是以小堆为例

如何创建小堆?

首先我们只会得到一个数组,并且我们知道堆最终形态是完全二叉树。通过递归的思想,如果能把最后一个以非叶子结点为根的树变为小堆,然后改变倒数第二个以非叶子结点为根的树,以此类推就可以将整个树变为小堆。函数内需要用到向下调整法可看注释:

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);		//向下调整将改变之后的树变为小堆
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值