zoukankan      html  css  js  c++  java
  • 07_3.优先队列

    连续表实现优先队列:

    """基于list实现优先队列"""
    
    
    class PrioQueueError(ValueError):
        pass
    
    
    class PrioQueue:
        """
        数据的存储位置按优先顺序排列
        值较小的元素优先级更高
        """
    
        def __init__(self, elist=[]):
            self._elems = list(elist)  # 默认值是可变对象,用list转换,做一个拷贝,避免共享
            self._elems.sort(reverse=True)
    
        def enqueue(self, e):
            i = len(self._elems) - 1
            while i >= 0:
                if self._elems[i] <= e:
                    i -= 1
                else:
                    break
            # while结束,i为-1或第一个大于e的元素的下标
            self._elems.insert(i + 1, e)
    
        def is_empty(self):
            return not self._elems
    
        def peek(self):
            if self.is_empty():
                raise PrioQueueError('in top')
            return self._elems[-1]
    
        def dequeue(self):
            if self.is_empty():
                raise PrioQueueError('in pop')
            return self._elems.pop()
    
    
    p = PrioQueue([1, 2, 3, 4])
    print(p._elems)
    p.enqueue(5)
    print(p._elems)

    采用线性表实现优先队列,无论是连续表还是链表,在插入元素与取出元素的操作中总有一种是具体线性复杂度的操作

     优先队列的堆实现:

    """基于堆(小顶堆)实现优先队列
    堆中每个结点的数据均小于或等于其子结点的数据
    解决堆插入和删除的关键操作称为筛选,分向上筛选,向下筛选
    去掉一个堆中最后的元素(最下层的最右结点),剩下的元素仍构成一个堆
    - 插入元素:
        在一个堆的最后加入一个元素,得到的结果还可以看作完全二叉树,但未必是堆,需要做一次向上的筛选
    - 向上筛选:
        不断用新加入的元素(e)与其父结点的数据比较,如果e较小就交换两个元素的位置,通过比较和交换,元素e
    不断上移,一直到e的父结点的数据<=e时,或者e已经到达根结点时停止。
    
    插入操作总结:把新加入元素放在(连续表里)已有元素之后,执行一次向上筛选操作。向上筛选操作中比较和交换的
    次数不会超过二叉树中最长路径的长度,根据完全二叉树性质,加入元素操作可在O(logn)时间完成
    - 弹出元素:
        由于堆顶元素就是最优元素,应该弹出的元素就是它,剩下的团扇可以看作两个子堆,从原堆的最后取下一个元素,
    其余的元素仍然是堆,把这个元素放到堆顶就得到了一棵完全二叉数,需要做向下筛选恢复为一个堆
    - 向下筛选:
        两个子堆A,B的顶元素与原堆取的最后一个元素e比较大小,最小者作为整个堆的顶
        * 若e不是最小,最小的必为A或B的根,如果A的最小,将其移到堆顶,相当于删除了A的顶元素
        * 如果某次比较中e最小,以它为顶的局部树已经成为堆,整个结构也成为堆
        * 或e已经落到底,这是整个结构也成为堆
    """
    
    
    class PrioQueueError(ValueError):
        pass
    
    
    class PrioQueue:
        """使用一个list存储元素,表尾加入元素,以首端为堆顶"""
    
        def __init__(self, elist=[]):
            self._elems = list(elist)
            if elist:
                self.buildheap()  # 转变为堆
    
        def enqueue(self, e):
            self._elems.append(None)
            self.siftup(e, len(self._elems) - 1)
    
        # 向上筛选
        def siftup(self, e, last):
            elems, i, j = self._elems, last, (last - 1) // 2  # (last - 1) // 2 :最后一个元素的根元素位置
            # 小顶堆,找到正确插入位置,检查过程中逐个下移
            while i > 0 and e < elems[j]:
                elems[i] = elems[j]
                i, j = j, (j - 1) // 2
            elems[i] = e
    
        def is_empty(self):
            return not self._elems
    
        def peek(self):
            if self.is_empty():
                raise PrioQueueError('in top')
            return self._elems[0]
    
        def dequeue(self):
            """弹出元素"""
            if self.is_empty():
                raise PrioQueueError('in pop')
            elems = self._elems
            e0 = elems[0]  # 堆顶元素
            e = elems.pop()  # 弹出最后元素
            if len(elems) > 0:
                self.siftdown(e, 0, len(elems))
            return e0
    
        # 向下筛选
        def siftdown(self, e, begin, end):
            """采用拿着新元素找位置"""
            elems, i, j = self._elems, begin, begin * 2 + 1  # begin * 2 + 1: 第一个小堆的堆顶
            while j < end:
                if j + 1 < end and elems[j + 1] < elems[j]:  # 找elems[j + 1]与elems[j]中较小的
                    j += 1
                if e < elems[j]:  # e在三者中最小,已找到了位置
                    break
                elems[i] = elems[j]  # elems[j]在三者中最小,上移
                i, j = j, 2 * j + 1
            elems[i] = e
    
        def buildheap(self):
            end = len(self._elems)
            for i in range(end // 2, -1, -1):
                self.siftdown(self._elems[i], i, end)
    
    
    p = PrioQueue([1, 3, 6, 4, 5])
    print(p._elems)
    print('========')
    print(p.dequeue())
    print(p.dequeue())
    print(p.dequeue())
    print(p.dequeue())
    print(p.dequeue())
    
    # [1, 3, 6, 4, 5]
    # ========
    # 1
    # 3
    # 4
    # 5
    # 6

     基于堆实现优先队列,创建操作的时间复杂度是o(n),插入和弹出的复杂度是o(log n)插入操作的第一步是在表的最后加入一个元素,可能导致list对象替换元素存储区,因此可能出现O(n)的最坏情况

  • 相关阅读:
    关于多重条件的搜索查询(sql server+c#)
    sqlserver2005安装错误:性能监视器计数器要求:SQL Server 2005 中为安装程序增加计数器注册表项值....
    javascript动态网页编程实例手册--学习笔记
    asp与asp.net共用session
    如何备份和还原虚拟主机上的数据库到本地
    sql server cannot delete last ''...
    SQL Server 2000的企业管理器无法打开
    asp.net2.0(c#)关于画图的一个例子;
    JBOSS SOA Platform
    C#编译开关
  • 原文地址:https://www.cnblogs.com/fly-book/p/11746661.html
Copyright © 2011-2022 走看看