首页 > 学院 > 开发设计 > 正文

优先队列-堆

2019-11-06 06:23:13
字体:
来源:转载
供稿:网友

优先队列

  队列是一个操作受限的线性表,数据只能在一端进入,另一端出来,具有先进先出的性质。有时在队列中需要处理优先级的情况,即后面进入的数据需要提前出来,这里就需要优先队列。优先队列是至少能够提供插入和删除最小值这两种操作的数据结构。对应于队列的操作,插入相当于入队,删除最小相当于出队。   链表,二叉查找树,都可以提供插入和删除最小这两种操作。对于链表的实现,插入需要O(1),删除最小需要遍历链表,故需要O(N)。对于二叉查找树,这两种操作都需要O(logN);而且随着不停的删除最小的操作,二叉查找树会变得非常不平衡;同时使用二叉查找树有些浪费,因此很多操作根本不需要。一种较好的实现优先队列的方式是二叉堆(下面简称堆)。   

  堆实质上是满足如下性质的完全二叉树:树中任一非叶结点的关键字均不大于(或不小于)其左右孩子(若存在)结点的关键字。首先堆是完全二叉树(只有最下面的两层结点度能够小于2,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树),其次任意节点的左右孩子(若有)值都不小于其父亲,这是小根堆,即最小的永远在上面。相反的是大根堆,即大的在上面。   因为完全二叉树有很好的规律,因此可以只用数据来存储数据而不需要链表。如下图:   这里写图片描述   如图保存在数组中的数据A~J,对于任意位置i,其左儿子在数组中位置为2i,其右儿子在数组中位置为2i+1,其父亲位置在floor(i/2)。      堆的插入:插入堆,那么堆中元素将加一,会在最后一个叶子后添加一个叶子,如上图中的J后面。添加了一个叶子后,需要按照大小比较将这个值放到特定的位置,直到满足堆条件,这是个上滤过程。   堆的删除最小:删除堆中最小的一个,对于小根堆来说就是删除根,删除根后,需要将下面的元素按照大小规则往上移,直到删除最后一个叶子,这是个下滤过程。   建堆的时间复杂度为O(N),删除堆最小值的时间复杂度为O(logN),N为节点数。

定义一个堆结构并实现数据插入和删除最小值操作:

#define max 20struct queue{ int size; int data[max];};//insert a data to queue;void insert(queue &q, int x){ int tmp = q.size; //store data at the first site data[0] q.data[tmp] = x; while ((tmp-1)/2>=0) { if(q.data[tmp] < q.data[(tmp-1)/2]) { q.data[tmp] = q.data[(tmp-1)/2]; q.data[(tmp-1)/2] = x; tmp = (tmp-1)/2; }else break; // } q.size++;}//delete the minimum data in the queuevoid deletemin(queue &q){ int tmp = 0; while (tmp*2+2 < q.size) { if(q.data[tmp*2+1]<q.data[tmp*2+2]) { q.data[tmp] = q.data[tmp*2+1]; tmp = tmp*2+1; } else { q.data[tmp] = q.data[tmp*2+2]; tmp = tmp*2+2; } } q.data[tmp] = q.data[q.size-1]; q.data[q.size-1] = 0; q.size--;}int main(){ queue q; q.size = 0; //it's necessary insert(q,7);insert(q,5);insert(q,2); insert(q,3);insert(q,1);insert(q,4); deletemin(q); for(int i=0; i<q.size; i++) cout << q.data[i]; return 0;}

参考:   优先队列及最小堆最大堆   PRiority Queue(Heaps)–优先队列(堆)

STL中的优先队列:priority_queue

  priority_queue为STL中实现的优先队列结构,输入存入队列会自动按照大根堆的性质保存。它的模板声明带有三个参数:   priority_queue<Type, Container, Functional> Type 为数据类型,Container 为保存数据的容器,Functional 为元素比较方式。Container 必须是用数组实现的容器,比如 vector, deque 但不能用 list。STL里面默认用的是 vector,比较方式默认用 Operator< , 所以如果你把后面俩个参数缺省的话,优先队列就是大顶堆,队头元素最大。   priority_queue<int,vector<int>,greater<int> >q3;//定义小的先出队

常用的函数:

  push() //插入一个数;  pop() //删除最小(大)的那个数;  front() //返回队首元素;  back() //返回队尾元素;  empty() //队列是否为空  size() //队列中元素个数

priority_queue定义在头文件queue中,在此文件中还有一种数据类型queue,即单向队列,基本操作也是上面的几个函数,与双向队列deque略有差别。 基本定义:queue<int> q;

int main(){ queue<int> s; priority_queue<int> ss; priority_queue<int,vector<int>,greater<int> >q3; s.push(1);s.push(2); s.pop(); ss.push(1);ss.push(4);ss.push(0);ss.pop(); q3.push(1);q3.push(4);q3.push(0);q3.pop(); return 0;}

对于自己定义的数据类型作为队列参数,用法参考:priority_queue的用法


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表