一、堆的基本概念
优先队列:
特殊的“队列”,取出元素的顺序是依照元素的优先权(或关键字大小,如权重),而不是进入队列的先后顺序。
堆的存储结构:是否可以采取形同二叉树的链表形式?
答:是可以的,但是由于堆经常需要加入和删除元素,采取不同的链表二叉树,可能会导致二叉树退化形成单链表,从而增加了树的高度,搜索复杂度增加。
堆的存取形式采取优先队列的完全二叉树
堆的性质:
1.结构性:堆是用数组表示的二叉树;
2.有序性:任一结点的关键字是其子树所有结点的最大值或最小值,即这种树称为最大堆或最小堆。
二、堆的抽象数据类型
ADT:
类型名称:最大堆
对象集:完全二叉树,每个结点的元素值不小于其子结点的元素值
操作集:创建最大堆,判断是否为空/满,插入,删除
typedef struct HeapStruct* MaxHeap;
struct HeapStruct{
ElementType *Elements;
int size;
int capacity;
};
三、最大堆的代码实现
#include<iostream>
#include<cmath>
using namespace std;
#define MAXDATA 100;//哨兵
typedef struct HeapStruct* MaxHeap;
struct HeapStruct
{
int *arr;
int size;//当前元素个数
int capacity;//最大容量
};
//建立最大堆
MaxHeap Create(int maxsize)
{
MaxHeap H = new struct HeapStruct;
H->arr = new int[maxsize+1];
H->size = 0;
H->capacity = maxsize;
H->arr[0] = MAXDATA;//哨兵元素
return H;
}
//判断是否为空
int IsFull(MaxHeap H)
{
if(H->size==H->capacity) return 1;
else return 0;
}
void Insert(MaxHeap H,int item)
{
int i;
if(IsFull(H))
{
cout << "最大堆已满"<<endl;
return;
}
i = ++H->size;
for(; H->arr[i/2]<item;i/=2)//其实如果最顶层元素仍比待插入元素小,那么还会继续往上顶,出现下标下益,解决方法加一个与条件:i>1,或者加一个哨兵,这里我没加
{
H->arr[i] = H->arr[i/2];
}
H->arr[i] = item;
}
//按路径遍历,输入一个结点号,会沿着一条该叶结点一路向上遍历
void Ergodic(MaxHeap H,int i)
{
for(;i>=1;i/=2)
{
cout << H->arr[i]<<endl;
}
}
int main()
{
MaxHeap H;
H = Create(9);//建立空堆
Insert(H,10);//依次插入9个元素
Insert(H,23);
Insert(H,26);
Insert(H,46);
Insert(H,24);
Insert(H,28);
Insert(H,36);
Insert(H,42);
Insert(H,0);
Ergodic(H,9);遍历其中一条路径,第9号是0,所以结果应为0,26,42,46
}
结果
对应插入形成的二叉树:懒得用word做了。。。
另附最大堆的删除:哈夫曼树中有实现堆删除的代码
Temp是取出的最大堆的最后一个元素,且容量-1
For循环从根节点开始,判定条件是是否有左儿子,parent*2=H->size是说左儿子的序号在当前容量之内,即左儿子存在。
Child是左儿子,然后比较该节点下的左右儿子大小,前提条件是右儿子也存在,即child!=H->size,即左儿子不是最后一个元素
比较完左右儿子后,再和temp比较
循环结束后,即从上向下过滤结束,parent等于要替换的值