1、定义:将优先级最高的元素先出队列的队列。
2、基本操作:入队(插入),出队(删除优先级最高的元素,代码中以元素值最小为优先级最高),构建堆,
修改元素等。
3、二叉堆:父节点小于子节点的完全二叉树。
性质:
(1)结构性:完全二叉树结构
(2)堆序性:父节点的值小于子节点的值
3、代码实现:
(1)堆的结构:用线性表顺序存储实现即可,不需要复杂的指针。
struct Node{ int *data; int Capcity,size; }; typedef struct Node* PriorityQueue;
(2)堆的插入(优先队列的入队):
先在数组后分配一个新的空间,然后寻找x要插入的位置,将x与大于它的父节点进行交换(上滤),
直到再次满足堆的堆序性。
void Insert(int x,PriorityQueue Q) //插入 { if(IsFull(Q)){ printf("The Queue is Full "); return ; } int i; for(i=++Q->size;Q->data[i/2]>x;i/=2) //上滤 Q->data[i]=Q->data[i/2]; Q->data[i]=x; }
(2)堆的删除最小值(优先队列的出队):
直接将头结点出队,然后不断向下调整,选取子节点中较小的值变为根节点,然后再调整改变较小的子节点(下滤),使堆重新有序。
int DeleteMin(PriorityQueue Q) //出队 { if(IsEmpty(Q)){ printf("The Queue is Empty!!! "); return -1; } int i,MI=Q->data[1],child,Last=Q->data[Q->size--]; for(i=1;i*2<=Q->size;i=child) //下滤 { child=i*2; if(Q->size!=child&&Q->data[child+1]<Q->data[child]) child++; if(Last>Q->data[child]) Q->data[i]=Q->data[child]; else break; } Q->data[i]=Last; return MI; }
(3)堆的上滤和下滤:
上滤:从要调整的值开始,不断将当前值向上移动,直到位置合适(画图更好理解)。
void PrecolateUp(int pos,PriorityQueue Q) //上滤 { int i,x=Q->data[pos]; for(i=pos;Q->data[i/2]>x;i/=2) Q->data[i]=Q->data[i/2]; Q->data[i]=x; }
下滤:与上滤相反
void PrecolateDown(int pos,PriorityQueue Q) //下滤 { int i,Last=Q->data[pos],child; for(i=pos;i*2<=Q->size;i=child) { child=i*2; if(child!=Q->size&&Q->data[child+1]<Q->data[child]) child++; //考虑是否有单个节点 if(Last>Q->data[child]) Q->data[i]=Q->data[child]; else break; } Q->data[i]=Last; }
(4)堆的修改:
增值:先增加当前值,然后下滤
void IncreaseKey(int pos,int x,PriorityQueue Q) { if(IsEmpty(Q)) return ; Q->data[pos]+=x; PrecolateDown(pos,Q); }
降值:先减小当前值,然后上滤
void IncreaseKey(int pos,int x,PriorityQueue Q) { if(IsEmpty(Q)) return ; Q->data[pos]+=x; PrecolateDown(pos,Q); }
(5)堆的删除:
先将这个值减小为负无穷,再删除最小值。
void Delete(int pos,PriorityQueue Q) //删除某一位置的元素 { if(IsEmpty(Q)) return ; int tmp=INT_MAX,i; DecreaseKey(pos,tmp,Q); DeleteMin(Q); }
(6)构建堆:
从叶子节点的父节点开始调整,使第i层及以下序列有序,然后向上调整(用于堆排序)。
void BuildHeap(PriorityQueue Q) //构建堆 { for(int i=Q->size/2;i>0;i--) PrecolateDown(i,Q); }
总代码:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn = 1200; const int MINSIZE = 3; struct Node{ int *data; int Capcity,size; }; typedef struct Node* PriorityQueue; PriorityQueue Init(int size) //初始化 { PriorityQueue Q=new Node; if(Q==NULL) printf("Ouf of Space!!! "); if(size<MINSIZE) printf("Too Small "); Q->data=new int[size+1]; if(Q->data==NULL){ printf("Ouf of Space!!! "); } Q->Capcity=size; Q->size=0; Q->data[0]=INT_MIN; return Q; } bool IsEmpty(PriorityQueue Q) { return Q->size==0; } bool IsFull(PriorityQueue Q) { return Q->size>Q->Capcity; } void PrecolateUp(int pos,PriorityQueue Q) //上滤 { int i,x=Q->data[pos]; for(i=pos;Q->data[i/2]>x;i/=2) Q->data[i]=Q->data[i/2]; Q->data[i]=x; } void PrecolateDown(int pos,PriorityQueue Q) //下滤 { int i,Last=Q->data[pos],child; for(i=pos;i*2<=Q->size;i=child) { child=i*2; if(child!=Q->size&&Q->data[child+1]<Q->data[child]) child++; //考虑是否有单个节点 if(Last>Q->data[child]) Q->data[i]=Q->data[child]; else break; } Q->data[i]=Last; } void Insert(int x,PriorityQueue Q) //插入 { if(IsFull(Q)){ printf("The Queue is Full "); return ; } int i; for(i=++Q->size;Q->data[i/2]>x;i/=2) //上滤 Q->data[i]=Q->data[i/2]; Q->data[i]=x; } //修改 void DecreaseKey(int pos,int x,PriorityQueue Q) { if(IsEmpty(Q)) return ; Q->data[pos]-=x; PrecolateUp(pos,Q); } void IncreaseKey(int pos,int x,PriorityQueue Q) { if(IsEmpty(Q)) return ; Q->data[pos]+=x; PrecolateDown(pos,Q); } void BuildHeap(PriorityQueue Q) //构建堆 { for(int i=Q->size/2;i>0;i--) PrecolateDown(i,Q); } int DeleteMin(PriorityQueue Q) //出队 { if(IsEmpty(Q)){ printf("The Queue is Empty!!! "); return -1; } int i,MI=Q->data[1],child,Last=Q->data[Q->size--]; for(i=1;i*2<=Q->size;i=child) //下滤 { child=i*2; if(Q->size!=child&&Q->data[child+1]<Q->data[child]) child++; if(Last>Q->data[child]) Q->data[i]=Q->data[child]; else break; } Q->data[i]=Last; return MI; } void Delete(int pos,PriorityQueue Q) //删除某一位置的元素 { if(IsEmpty(Q)) return ; int tmp=INT_MAX,i; DecreaseKey(pos,tmp,Q); DeleteMin(Q); } void Print(PriorityQueue Q) { while(!IsEmpty(Q)){ int x=DeleteMin(Q); printf("%d ",x); } printf(" "); } int main(void) { int n,i,x; scanf("%d",&n); PriorityQueue Q=Init(n); for(i=0;i<n;i++) { scanf("%d",&x); Insert(x,Q); } IncreaseKey(3,99,Q); DecreaseKey(5,1000,Q); Delete(1,Q); Print(Q); return 0; } /* 测试数据: 5 12 34 11 5 6 */