zoukankan      html  css  js  c++  java
  • -------------------siwuxie095

       

       

       

       

       

       

       

       

    为什么使用堆

       

       

    这里介绍一个全新的数据结构:(Heap)

       

    的一个非常典型的应用就是 优先队列(Priority Queue)

       

       

       

    相信对于队列这个概念,大家都非常熟悉,如下:

       

    1普通队列:先进先出,后进后出

       

    在生活中,大家接触的通常是这种普通队列,所谓普通队列,它的关键

    其实是由时间的顺序来决定出队的顺序(即 入队顺序决定出队顺序

       

       

    2优先队列:出队顺序和入队顺序无关,和优先级相关

       

    所谓优先队列,是指对于排队的人、任务、或 等待执行的请求,

    它们都是具有一定的优先级的,出队的顺序和入队的顺序无关,

    而和优先级相关(即 优先级决定出队顺序

       

       

       

       

       

    实际上在生活中,很多情况也是采取优先队列的方式

       

    如:在一些医院看病时,就是急诊病人优先,虽然急诊病人到的可能

    比普通病人要晚,但由于普通病人的病情没有那么紧急,所以不会先

    被接收诊治

       

       

       

    优先队列在计算机科学中也被大量的使用,最典型的应用情况就是在操

    作系统中执行任务

       

    大家都知道操作系统要同时执行多个任务,但实际上操作系统是将 CPU

    的执行周期划成了时间片,在每个时间片里只能执行一个任务

       

    究竟要执行哪个任务呢?答案就是每个任务都有一个优先级,操作系统

    每一次将动态的选择优先级最高的任务进行执行

       

    那么要想能够动态选择优先级最高的任务执行,就需要使用优先队列

       

    操作系统中的所有任务都进入优先队列,由优先队列来调度操作系统

    每次执行哪个任务

       

    注意:这里有一个关键词,即 动态

       

    不难想象,如果所有任务永远是固定的话(即 就那么几个任务且优先级

    没变化),那么完全可以把这些任务就排一次序,然后从优先级最高到

    优先级最低依次执行即可

       

       

       

    可是当实际使用优先队列时,情况通常都非常复杂,可以用一个模型模拟如下:

       

       

       

    在上图中,蓝色大圆圈表示一个任务处理中心,红色小圆圈表示一个个请求

    通过任务处理中心来处理所有的请求

       

    当任务处理中心选择执行了某一个请求之后,下一步可能不是简单的去执行

    其它的请求,因为在执行该请求的同时,有可能又来了很多新的请求,而且

    旧的请求的优先级本身也有可能发生改变

       

    所以在这种情况下,一次性的将所有请求排序,然后依次执行,是不现实的,

    如果使用排序的方式来解决这个问题,很有可能每一次执行完了某一个请求

    之后,都要再对剩下的请求进行一次新的排序,但这样做,耗时是巨大的

       

       

       

    当然,这种模型不仅仅适用于操作系统,事实上,在现在的生活中处处都存

    在着这样的模型,如:在上网时,不同用户会对同一个网络页面产生网络请

    求,而服务器端就要依次来回应这些请求,回应的顺序是怎样决定的,通常

    就是通过优先队列来决定

       

       

       

    在媒体服务、视频播放、音乐播放等领域,全部都需要使用优先队列,而

    在人工智能领域也要使用优先队列

       

    如:在游戏中,可能需要用智能来决定某一个角色去攻击敌人的顺序,在

    这种情况下,通常这个角色会有一个视野,比较专业的说法叫做 AOI,也

    就是这个角色所感兴趣的一个范围

       

    在这个范围中,可能有若干个敌人,这个角色就需要由电脑控制,在这些

    敌人中选择一个进行攻击,这个选择的顺序,通常就是一个优先队列决定

    的顺序,如:可能每次选择最强的那个敌人进行攻击,或 血最少的那个敌

    人进行攻击

       

    显然,优先队列使用的场景主要是处理动态的情况,因为随着游戏的进行,

    这个角色会将攻击范围里的敌人逐渐消灭掉,与此同时,还有很多敌人会

    逐渐进入这个角色的攻击范围

       

    因此,就需要不断向优先队列中入队新的敌人,与此同时,出队根据优先

    队列所选择出来的最佳攻击对象(敌人)

       

       

       

       

     

    在上面的例子中,我们一直强调优先队列非常适合处理数据是动态的情况,

    但实际上在一些静态的问题的求解上,优先队列也是非常有优势的,如下:

       

       

    题目:在 1000000 个元素中选出前 100

       

    现在有一百万个元素,想在这一百万个元素中选出前一百名,

    应该怎么做?

       

    把这个问题抽象一下,即:在 N 个元素中选出前 M 个元素

       

       

    大家都能想出的一个基本解法是:只要把这 N 个元素进行一次

    排序,然后选出它的前 M 个元素即可,这样的解决方案,算法

    的复杂度是 N*logN 这个级别的

       

    但如果使用了优先队列,就能把算法复杂度降低到 N*logM

    个级别

       

       

    具体到这个例子中,N 是一百万,M 是一百,这样的一个优化

    将使算法快十几倍,当然,如果 N 更大,这个优化的性能优势

    将更加明显

       

       

    那么优先队列是如何将这样一个问题的时间复杂度从 N*logN

    降到 N*logM 呢?这就涉及到优先队列的实现了

       

       

       

       

       

    对于队列来说,它的主要操作有两个:一个叫做入队,一个叫做出队

       

    优先队列也不例外,从用户的角度来看,优先队列最大的特点就是在

    出队时,取出优先级最高的元素

       

       

       

    优先队列的实现方式

       

      

    入队

    出队

    普通数组

    O(1)

    O(n)

    顺序数组

    O(n)

    O(1)

    O(lgn)

    O(lgn)

       

       

    通过数组这样的数据结构就完全可以实现一个优先队列,有两种思路:

       

    1)使用普通数组,这样入队就非常简单,使用 O(1) 的时间,直接把一个

    元素扔到数组末尾即可,而在出队时,为了取出优先级最高的元素,需要

    使用 O(n) 的时间,扫描一遍当前数组,然后拿出优先级最高的元素

       

    2)使用顺序数组,也就是要不断的维护这个数组的有序性。这样一来,在

    元素入队时,就需要使用 O(n) 的时间,来找到合适的插入位置,而一旦维

    护好了数组的有序性,出队就非常简单,使用 O(1) 的时间,直接把队头的

    那个优先级最高的元素扔出去即可

       

       

       

    但是使用数组进行优先队列的实现是有局限性的,伟大的计算机科学家

    发明了一种新的数据结构,可以非常好的平衡入队和出队这两个操作的

    时间复杂度

       

    这种数据结构 ,使用 可以将入队和出队的时间效率都变成 lgn

    这个级别的

       

       

    不难发现,对于 lgn 这个级别的时间复杂度来说,它在入队这个时间上

    慢于普通数组,在出队这个时间上也慢于顺序数组

       

    但平均来讲,使用堆这种数据结构维持一个优先队列,来完成一个系统

    任务,它所用的时间要大大低于使用数组来进行实现

       

       

    最极端的情况,即 总共有 N 个请求:

       

    1)使用普通数组 顺序数组,时间复杂度:O(n^2)

       

    2)使用堆,时间复杂度:O(n*lgn)

       

       

    n^2n*lgn 这两个级别的算法,它们之间的差异是巨大的

       

       

       

       

       

       

       

       

       

       

    【made by siwuxie095】

  • 相关阅读:
    [leetcode]Remove Nth Node From End of List
    [leetcode]Palindrome Number
    [leetcode]Integer to Roman
    HDU 4709:Herding
    HDU 4708:Rotation Lock Puzzle
    HDU 4707:Pet
    HDU 4706:Children's Day
    SDUT 2411:Pixel density
    SDUT 2413:n a^o7 !
    SDUT 2409:The Best Seat in ACM Contest
  • 原文地址:https://www.cnblogs.com/siwuxie095/p/6946728.html
Copyright © 2011-2022 走看看