利用堆实现优先级队列博文

                       算法研究(四)

                 用堆实现优先级队列

   首先声明:本人只是一个菜鸟而已。。。。。。。

由于以后很多地方都会用到优先级队列的知识,所以在这里先给大家讲解一下。只是简单的说明一下而已,并没有深入的研究。

其实优先级队列的应用非常广泛,比如说最大优先级队列就用在一台分时计算机进行作业调度。这种队列对要执行的各种作业以及他们之间的相对优先级关系加以记录。当一个作业做完或是被中断时,用extract_max操作从所有等待的作业中,选择出具有最高优先级的作业。在任何时候一个新的作业都可以用insert加入到队列中去。

而最小优先级队列可被用在基于事件驱动的模拟器中。在这种应用中,队列中的各项是要模拟事件,每一个都有一个发生时间作为关键字。事件模拟要按照各事件发生时间的顺序进行,因为模拟某一事件可能导致稍后对其他事件的模拟。模拟程序的每一步都使用extrac_min来选择下一个模拟的事件。当一个新事件产生时,使用insert将其放入队列中。

所以大家也可以看出优先级队列确实很重要,不仅如此,大家以后在看我的博文还会不止一次的遇到什么赫夫曼树,B树,二项堆。。。。。。废话说了不少,直接入主题。

给大家讲解一下用堆实现优先级队列的各种操作(这里以最大优先级队列为例,最小优先级队列相似不再赘述):

堆用heap[n]表示

1、     求MAXIMUM

   说了利用堆实现,最大优先级队列对应的利用大顶堆实现。既然是大顶堆,我们知道堆顶的元素就是最大元素,所以我们可以直接返回堆顶元素:

return heap[1];

2、     取出最大元素

  上面的操作只是返回最大元素,没有真正从堆中取出最大元素,就像在赫夫曼树中一样,每次必须从树中取出两个频度最小的结点,在树中就没有这两个结点了。这里也是一样。我们需要注意的就是取出操作会破坏大顶堆的性质,我们要做的就是对堆进行变化使其可以再次符合大顶堆的性质。看过利用大顶堆的同学肯定已经想到了,对,就是利用max_heapify这个函数去实现对性质的稳定。分析过后,我们给出代码:

heap_extract_max(int *heap)

{

f(heap_size < 1)

     {

          cout<<"heapis empty!"<<endl;

          exit(1);//异常退出

     }

     int max =heap[1];

     heap[1] =heap[heap_size];

     heap_size--;

     max_heapify(heap,1);

     return max;

}

 

3、     增大某个元素的值

   和取出最大元素的情况类似,我们同样可能会因为增大某个元素的值而导致我们的操作破坏了大顶堆的性质。操作也很类似,我们在取出最大元素时,是从结点1开始破坏的,所以我们必须从1开始重新稳定大顶堆。在这里我们破坏了某个元素的大小,所以可以联想我们也是从这个元素开始稳定,但是这里相对就简单多了,因为我们只要和该结点的双亲比较即可,因为原先它比双亲小,现在增大以后可能大于双亲了,但是其兄弟并没有变化,所以每次只要不断上传并与其双亲交换,直到它比双亲结点小即可。

//增大指定元素的大小

void heap_increase_key(int *heap, int pos, int key)

{

     if(key <heap[pos])

     {

          cout<<"newkey is smaller than current key!"<<endl;

          exit(1);

     }

     heap[pos] =key;

     while(pos> 1 && heap[parent(pos)] < heap[pos])//当双亲大于孩子时结束

     {

          int t =heap[parent(pos)];

          heap[parent(pos)]= heap[pos];

          heap[pos]= t;

          pos =parent(pos);//一直往上寻找

     }

}

4、     插入操作

   插入操作的代码并不难,也容易记住,但是值得我们注意的是它的思想,这个很值得我们去好好思考思考。我们想要在大顶堆插入一个元素,常规的我们可能会想像二叉查找树那样,但是那样未免太麻烦了。这里我们有了更好的做法,并且时间复杂度也很好。我们现在大顶堆的末尾插入一个最小的元素,这从开始插入就符合大顶堆的性质(与之对应的是在最小优先级队列中,插入的是最大元素)所以在以后再改变这个元素的值,这样就可以通过我们上面的那个增大元素值的函数,代码也同样无需重写,大家感觉这是不是一种比较好的思想呢?反正我是感觉这样挺好的。。

说完了直接给出代码:

void max_heap_insert(int *heap, int key)

{

     heap[++heap_size]= -INT_MAX;

     heap_increase_key(heap,heap_size, key);

}

利用堆实现优先级队列就到这里,很简短,但是却很重要,希望大家可以好好消化一下。

完整代码我已经在我的另一篇博文里面给大家了,写的不好或是有错的地方希望大家能够提醒我。大家好,才是真的好嘛!不是吗?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值