1.堆常用来实现优先级队列,优先级队列的删除操作是以队列元素的优先级高低为准,
一般删除优先级最高或者最低的元素,而优先级队列的插入操作并不限制元素的优先级
2.堆是一个完全二叉树
堆一般用数组的形式来表示
3,堆分为大顶堆和小顶堆
3.1大顶堆的特点是根的元素大于孩子的元素,小顶堆则相反
下面我们来共同实现创建堆和删除堆顶元素
//注意我用数组下标为1保存堆顶,想想这是为什么,答案很简单,从下标1开始保存,可以发现左孩子的下标刚好等于双亲下标的2倍,左孩子和右孩子之间相差1,这样就很容易表示
层数,双亲结点和孩子结点之间的关系
#include<stdlib.h>
#include<stdio.h>
typedef struct
{
int *pnData;//指向堆里结点数据的指针
int nSize;//当前堆中元素的个数,
}Myheap;//堆
int IncreaseKey(Myheap*pheap, int nPos) //进行比较调整新插入结点的位置
{
while (nPos > 1)//循环和他的双亲结点比较
{
int nMax = pheap->pnData[nPos];//临时变量,存取新插入结点的值
int nParent = nPos / 2;
if (nMax > pheap->pnData[nParent])//向上渗透
{
pheap->pnData[nPos] = pheap->pnData[nParent];
pheap->pnData[nParent] = nMax;
nPos = nParent;//向上移动
}
else
{
break;
}
}
return 1;
}
int Insert(Myheap *pheap,int nData)//插入新节点
{
++pheap->nSize;//堆的结点数会+1
//从1开始插入
pheap->pnData[pheap->nSize] = nData;
IncreaseKey(pheap, pheap->nSize);//将刚刚插入的数和位置与堆进行比较,从底层向上渗透
return 1;
}
int PopMaxHeap(Myheap *pheap)//得到堆中根结点的关键字,并弹出堆中最大的数
{
int nMax = pheap->pnData[1];//得到堆最大值
int nPos = 1;
int nChild = nPos * 2;//得到左孩子结点
while (nChild <= pheap->nSize)//左孩子的下标不可以超出最大下标
{
int nTemp = pheap->pnData[nChild];//目的保存根节点左右孩子的最大的那个孩子
if (nChild + 1 <= pheap->nSize&&nTemp < pheap->pnData[nChild + 1])//右孩子大于左孩子的值
{
++nChild;//
nTemp = pheap->pnData[nChild]; //保存最大的右孩子
}
pheap->pnData[nPos] = nTemp; //将最大的孩子元素给pnos
//以上代码用于比较根结点的左右孩子大小,如果谁大就赋值给根结点
nPos = nChild; //因为孩子结点空了,就保存当前结点为根节点,重复上面的
nChild *= 2; //进入下一层
}
pheap->pnData[nPos] = pheap->pnData[pheap->nSize];
--pheap->nSize;//减少一个元素,
return nMax;
}
int main()
{
Myheap myheap;//创建一个空堆
myheap.pnData = (int *)malloc(sizeof(int)*11);//空堆
myheap.nSize = 0;//初始化0
for (int i = 1; i <= 10; i++)
{
Insert(&myheap, i);//不断插入结点
}
printf("输出\n");
for (int i = 1; i <= 10; i++)
{
printf("%d ", myheap.pnData[i]);
}
printf("弹出\n");
while (myheap.nSize > 0)
{
printf("%d " ,PopMaxHeap(&myheap));
}
printf("\n");
system("pause");
return 0;
}