优先队列【转帖】

 

哎,虽然因为对于 NOIP 信息奥赛的厌恶让我对于数据结构的全面学习延迟到了现在,但是我依然想要呐喊一句:我讨厌信息奥林匹克这个无聊的比赛!

不过这几天系统地开始学习数据结构,其实每一个数据结构都有无穷的威力,就连我以前嗤之以鼻的图论算法,这两天看来,也是很值得一学的了。也罢,就做做数据结构的笔记吧。

首先要说的是优先队列。

为什么不从表、栈、队列这种最简单的结构开始呢?我觉得没必要,自己看没必要,别人更没必要。

优先队列,即在普通队列的 ADT 上加了一重逻辑,让符合某种条件的元素优先出队。一般以数值大小为条件,所以也分为最大化优先队列和最小化优先队列。

优先队列的核心实现是一个堆。

堆是一种特殊的数据结构。它是一棵二叉树,元素必须从左至右填入最后一层,然后再创建新一层。因此堆满足很多有趣的性质:

1)若堆的元素个数为 N,则高度不超过 [log N] + 1。

2)优先队列可以用数组表示。在这种情况下,节点 N 的父节点在 N/2 处,左子节点在 N*2 处,右子节点在 N*2+1 处。

这两条性质是优先队列高效 ADT 实现的基础。

优先队列在堆的基础上规定:父节点不能大于、或小于子节点——这取决于是最大化堆、还是最小化堆。

优先队列的思想其实也很简单。首先构造一个堆(这个不用解释了吧)。

 

    我做的是最小化堆,并在 Q.data[0] 处做了一个哑元。这样的好处之一是完全符合 N、N/2、N*2、N*2+1 的序号规则(试想一下 0/2、0*2、0*2+1 …… 寒毛耸立)。其二是入队的工作非常方便。

    入队的主要思想是“上滤”。何为上滤?看看下面一个优先队列:

    4
    -5
    --7
    --10
    -6
    

    可以看得出来这个堆是符合优先队列的 ADT 的。现在为了插入元素 3,我们必须在数组最后的一项创建一个空穴。

    4
    -5
    --7
    --10
    -6
    --[3]
    

    这个 3 的引入彻底破坏了 ADT。为了让 3 符合规则,这一步,我们需要将它与 6 交换位置。

    4
    -5
    --7
    --10
    -[3]
    --6
    

    依旧不符合,我们再上滤,直到根。

    [3]
    -5
    --7
    --10
    -4
    --6
    

    终于符合优先队列的 ADT 了!这也是用一个哑元的用意——不用判断是否到达根,只要哑元足够小,到了根自然会停下来。

    但是,有一个问题,就是重复元的问题。如果重复元比原有元上滤得多,那么将破坏队列的性质(先进先出)。于是我们在比较的时候,要特别留意。

    给出我的 Enqueue 代码(没有实际测试重复元问题,只是理论上验证了先进先出的性质)。

     

      时间要求高的地方可以免除检查,恩~

      还有出队。出队似乎很简单,由于一切都已就绪,那么返回根元素就可以了。但这就在根元素处形成了一个空穴,必须依赖于“下滤”——与“上滤”的思想基本一致。

      给出代码。

       

        出队麻烦得多,因为没有哑元的辅助,从代码上看效率要略低于入队。

        至于优先队列的 IncreaseKey 与 DecreaseKey,完全可以用上滤、下滤的思想完成,不再赘述。只是必须知道元素所在数组下标,这就丧失了优先队列 ADT 的纯洁性。
        另外,Delete 操作可以先 DecreaseKey,再 Dequeue。(这个过程我没有具体实现,其实也就是上滤的操作)。

        P.S. 优先队列与“堆排序”有非常深的关系。后来我尝试使用这个例程对 100000 个数据进行排序,效果还不错;当然比起快排还是嫌慢了点。

         

        评论
        添加红包

        请填写红包祝福语或标题

        红包个数最小为10个

        红包金额最低5元

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

        抵扣说明:

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

        余额充值