5.1 堆
当需要存储一个不同优先级的优先队列时(删除都删除最大/最小值,插入任意元素),我们就要用到堆,当然,用数组,链表,或树都可以完成,但是算法复杂度不够理想。
堆是一种特殊的树,它的任意节点都比它的左右儿子大/小,所以它的根节点是最大的/或者是最小的,删除的时候只需要删除最上面的根节点即可,插入时,为了使空间利用率最大,按照完全二叉树插入,这就是最大/小堆
还记得刚开始说二叉树的时候,我们试过用数组存储二叉树,然而因为利用率不高,只适合存完全二叉树这种排的比较满的树,对于现在堆这种结构,我们就可以用数组来存,从上到下一层一层排序,第i个节点左儿子是2*i,右儿子是2*i+1,父节点是i/2。
堆的抽象数据类型描述:
类型名称:最大堆(MaxHeap)
数据对象集:完全二叉树
操作集:
MaxHeap Create(int MaxSize);
Boolean IsFull(MaxHeap H);
Boolean IsEmpty(MaxHeap H);
MaxHeap Insert(ElementType x, MaxHeap H);
ElementType Delete(MaxHeap H);
最大堆的结构
typedef struct HeapStruct *MaxStruct;
struct HeapStruct{
//指向数组
ElementType *Elements;
//现有元素个数
int Size;
//最大容量
int Capacity;
};
创建一个最大堆
MaxHeap Create(int MaxSize){
MaxHeap H = malloc(sizeof(struct HeapStruct));
//数组空出一个位置存放最大值作为哨兵
H->Elements = malloc(sizeof((MaxSize+1)*ElementType));
H->Size = 0;
H->Capacity = MaxSize;
//宏定义一个数据里面的最大可能值,插入时可以减少一个判断条件。
H->Elements[0] = MaxData;
return H;
}
插入
MaxHeap Insert(ElementType x, MaxHeap H){
int i;
if(IsFull(H)){
printf("已满!");
return NULL;
}
//改变最大堆信息的同时,告诉i应该插入的位置
i = ++H->Size;
for(;H->Elements[i/2] < x;i /= 2){
H->Elements[i] = H->Elements[i/2];
}
H->Elements[i] = x;
return H;
}
删除
ElementType Delete(MaxHeap H){
if( IsEmpty(H) ){
printf("堆空!");
return NULL;
}
ElementType MaxItem = H->Elements[1];
ElementType item;
int parent = 1;
int child;
item = H->Elements[H->Size--];
for(;2*parent <= H->Size;parent = child){
child = 2 * parent;
if( child != H->Size){
if( H->Elements[child] < H->Elements[child+1])
child++;
}
if(item >= H->Elements[child])break;
else
H->Elements[parent] = H->Elements[child];
}
H->Elements[parent] = item;
return MaxItem;
}
给定一个序列,创建一个堆,可以通过不断的插入,但是有效率更高的方法,先把序列存入完全二叉树中,然后从最后一个有儿子的节点开始调整,形成一个节点,他的左右儿子都是堆的递归
//这段代码未经验证,有什么问题希望能反馈给我……
MaxHeap Create(ElementType T[Size]){
MaxHeap H;
for(int i = 0; i < Size; i++)
H->Elements[++H->Size] = T[i];
int parent = H->Size/2;
int child;
ElementType t;
for(;parent>0;parent--){
for(;2*parent <= H->Size;parent = child){
child = 2 * parent;
if( child != H->Size){
if( H->Elements[child] < H->Elements[child+1])
child++;
}
if(H->Elements[parent] >= H->Elements[child])break;
else{
t = H->Elements[parent];
H->Elements[parent] = H->Elements[child];
H->Elements[child] = t;
}
}
}
}