队列(基于Python)

队列

什么是对列?

​ 队列是一种列表,但是不同之处在于,队列只能在队尾插入元素,在队首删除元素。其只用于存储按顺序排列的数据,先进先出。这点和栈不一项,在栈中,最后入栈的元素反而被优先处理。

​ 可以合理把队列想象成在银行大厅排队的人群,排在最前面的人第一个办理业务,新来的只能在后面排队,直到轮到他们。

​ 计算机算法中的队列是一种特殊的线性表,只允许在表的前端进行删除操作,在表的后端进行插入操作,即最先插入的最先删除,最后插入的最后删除,称为“先进先出”(First In-First Out,FIFO)的线性表。队尾是进行插入操作的端,队头是进行删除操作的端。

抽象数据类型定义

ADT Queue{

数据对象:D={ai|ai∈ElementSet , i=1,2, …,n, n≥0}

数据关系:R1={<ai-1,ai>|ai-1,ai∈D, i=1,2, …,n }

约定a1为队列头,an为队列尾。

}

基本操作:

  1. InitQueue( &Q )
    操作结果:构造一个空队列Q。
  2. DestroyQueue ( &Q )
    初始条件:队列Q已存在。
    操作结果:销毁队列Q。
  3. ClearQueue ( &Q )
    初始条件:队列Q已存在。
    操作结果:将Q重置为空队列。
  4. QueueEmpty( Q )
    初始条件:队列Q已存在。
    操作结果:若Q为空队列,则返回TRUE,否则返回FALSE。
  5. QueueLength( Q )
    初始条件:队列Q已存在。
    操作结果:返回Q的数据元素个数,即队列的长度。
  6. GetHead( Q, &e )
    初始条件:队列Q已存在且非空。
    操作结果:用e返回Q的队头元素。
  7. EnQueue( &Q, e )
    初始条件:队列Q已存在。
    操作结果:插入元素e为Q的新的队尾元素。
  8. DeQueue( &Q, &e )
    初始条件:队列Q已存在且非空。
    操作结果:删除Q的队头元素,并用e返回其值。
  9. QueueTraverse( Q, visit() )
    初始条件:队列Q已存在且非空。
    操作结果:从队头到队尾依次对Q的每个数据元素调用函数visit()。一旦visit()失败,则操作失败。

python中常用的队列操作函数

  1. queue():定义一个空队列,无参数,返回值是空队列。

  2. enqueue(item):在队列尾部加入一个数据项,参数是数据项,无返回值。

  3. dequeue():删除队列头部的数据项,无需参数,返回值是被删除的数据,队列本身发生变化。

  4. IsEmpty():检测队列是否为空。无参数,返回布尔值。

  5. size():返回队列中的数据项数量。无参数,返回一个整数。

标准库中的队列

queue库

queue.Queue(maxsize=0)

FIFO类型

maxsize是一个整数,用于设置可放置在队列中的元素数量的上限。一旦达到这个大小,插入将被阻塞,直到队列中的元素被消耗掉。如果maxsize小于或等于零,则队列大小为无限大。

queue.LifoQueue(maxsize=0)

**LIFO **队列构造函数。

maxsize 是个整数,用于设置可以放入队列中的项目数的上限。当达到这个大小的时候,插入操作将阻塞至队列中的项目被消费掉。如果 maxsize 小于等于零,队列尺寸为无限大。

queue.PriorityQueue(maxsize=0)

优先级队列构造函数。 maxsize 是个整数,用于设置可以放入队列中的项目数的上限。当达到这个大小的时候,插入操作将阻塞至队列中的项目被消费掉。如果 maxsize 小于等于零,队列尺寸为无限大。

最小值先被取出( 最小值条目是由 sorted(list(entries))[0] 返回的条目)。条目的典型模式是一个以下形式的元组: (priority_number, data) 。

队列对象( Queue, LifoQueue, 或者 PriorityQueue) 提供下列描述的公共方法。
  1. Queue.qsize()
    返回队列的大致大小。注意,qsize() > 0 不保证后续的 get() 不被阻塞,qsize() < maxsize 也不保证 put() 不被阻塞。
  2. Queue.empty()
    如果队列为空,返回 True ,否则返回 False 。如果 empty() 返回 True ,不保证后续调用的 put() 不被阻塞。类似的,如果 empty() 返回 False ,也不保证后续调用的 get() 不被阻塞。
  3. Queue.full()
    如果队列是满的返回 True ,否则返回 False 。如果 full() 返回 True 不保证后续调用的 get() 不被阻塞。类似的,如果 full() 返回 False 也不保证后续调用的 put() 不被阻塞。
  4. Queue.put(item, block=True, timeout=None)
    将 item 放入队列。如果可选参数 block 是 true 并且 timeout 是 None (默认),则在必要时阻塞至有空闲插槽可用。如果 timeout 是个正数,将最多阻塞 timeout 秒,如果在这段时间没有可用的空闲插槽,将引发 Full 异常。反之 (block 是 false),如果空闲插槽立即可用,则把 item 放入队列,否则引发 Full 异常 ( 在这种情况下,timeout 将被忽略)。
  5. Queue.put_nowait(item)
    相当于 put(item, False)
  6. Queue.get(block=True, timeout=None)
    从队列中移除返回一个项目。如果可选参数 block 是 true 并且 timeout 是 None (默认值),则在必要时阻塞至项目可得到。如果 timeout 是个正数,将最多阻塞 timeout 秒,如果在这段时间内项目不能得到,将引发 Empty 异常。反之 (block 是 false) , 如果一个项目立即可得到,则返回一个项目,否则引发 Empty 异常 (这种情况下,timeout 将被忽略)。
  7. Queue.get_nowait()
    相当于 get(False) 。
  8. Queue.task_done()
    表示前面排队的任务已经被完成。被队列的消费者线程使用。每个 get() 被用于获取一个任务, 后续调用 task_done() 告诉队列,该任务的处理已经完成。
    如果 join() 当前正在阻塞,在所有条目都被处理后,将解除阻塞(意味着每个 put() 进队列的条目的 task_done() 都被收到)。
    如果被调用的次数多于放入队列中的项目数量,将引发 ValueError 异常 。
  9. Queue.join()
    阻塞至队列中所有的元素都被接收和处理完毕。
    当条目添加到队列的时候,未完成任务的计数就会增加。每当消费者线程调用 task_done() 表示这个条目已经被回收,该条目所有工作已经完成,未完成计数就会减少。当未完成计数降到零的时候, join() 阻塞被解除。
import Queue
q = Queue.Queue()
for i in range(5):
    q.put(i)
while not q.empty():
    print q.get()
#上面代码的输出
0
1
2
3
4

collections库

collections.deque([iterable[, maxlen]])

双端队列

返回一个新的双向队列对象,从左到右初始化(用方法 append()) ,从 iterable (迭代对象) 数据创建。如果 iterable 没有指定,新队列为空

Deque队列是由栈或者queue队列生成的(发音是 “deck”,”double-ended queue”的简称)。Deque 支持线程安全,内存高效添加(append)和弹出(pop),从两端都可以,两个方向的大概开销都是 O(1) 复杂度。

虽然 list 对象也支持类似操作,不过这里优化了定长操作和 pop(0) 和 insert(0, v) 的开销。它们引起 O(n) 内存移动的操作,改变底层数据表达的大小和位置。

如果 maxlen 没有指定或者是 None ,deques 可以增长到任意长度。否则,deque就限定到指定最大长度。一旦限定长度的deque满了,当新项加入时,同样数量的项就从另一端弹出。限定长度deque提供类似Unix filter tail 的功能。它们同样可以用与追踪最近的交换和其他数据池活动。

双向队列(deque)对象支持以下方法:
  1. append(x)
    添加 x 到右端。

  2. appendleft(x)
    添加 x 到左端。

  3. clear()
    移除所有元素,使其长度为0.

  4. copy()
    创建一份浅拷贝。

  5. count(x)
    计算 deque 中元素等于 x 的个数。

  6. extend(iterable)
    扩展deque的右侧,通过添加iterable参数中的元素。

  7. extendleft(iterable)
    扩展deque的左侧,通过添加iterable参数中的元素。注意,左添加时,在结果中iterable参数中的顺序将被反过来添加。

  8. index(x[, start[, stop]])
    返回 x 在 deque 中的位置(在索引 start 之后,索引 stop 之前)。 返回第一个匹配项,如果未找到则引发 ValueError。

9.insert(i, x)
在位置 i 插入 x 。
如果插入会导致一个限长 deque 超出长度 maxlen 的话,就引发一个 IndexError。

  1. pop()
    移去并且返回一个元素,deque 最右侧的那一个。 如果没有元素的话,就引发一个 IndexError。

  2. popleft()
    移去并且返回一个元素,deque 最左侧的那一个。 如果没有元素的话,就引发 IndexError。

  3. remove(value)
    移除找到的第一个 value。 如果没有的话就引发 ValueError。

  4. reverse()
    将deque逆序排列。返回 None 。

  5. rotate(n=1)
    向右循环移动 n 步。 如果 n 是负数,就向左循环。
    如果deque不是空的,向右循环移动一步就等价于 d.appendleft(d.pop()) , 向左循环一步就等价于 d.append(d.popleft()) 。

  6. maxlen
    Deque对象同样提供了一个只读属性:
    Deque的最大尺寸,如果没有限定的话就是 None 。

自己实现的基于列表的优先队列

#list实现优先队列

class ListPriQueueValueError(ValueError):
    pass

class List_Pri_Queue(object):
    def __init__(self, elems = []):
        self._elems = list(elems)
        #从大到小排序,末尾值最小,但优先级最高,方便弹出且效率为O(1)
        self._elems.sort(reverse=True)

    #判断队列是否为空
    def is_empty(self):
        return self._elems is []

    #查看最高优先级 O(1)
    def peek(self):
        if self.is_empty():
            raise ListPriQueueValueError("in pop")
        return self._elems[-1]

    #弹出最高优先级 O(1)
    def dequeue(self):
        if self.is_empty():
            raise ListPriQueueValueError("in pop")
        return self._elems.pop()

    #入队新的优先级 O(n)
    def enqueue(self, e):
        i = len(self._elems) - 1
        while i>=0:
            if self._elems[i] < e:
                i -= 1
            else:
                break
        self._elems.insert(i+1, e)

if __name__=="__main__":
    l = List_Pri_Queue([4,6,1,3,9,7,2,8])
    print(l._elems)
    print(l.peek())
    l.dequeue()
    print(l._elems)
    l.enqueue(5)
    print(l._elems)
    l.enqueue(1)
    print(l._elems)
#Output
[9, 8, 7, 6, 4, 3, 2, 1]
1
[9, 8, 7, 6, 4, 3, 2]
[9, 8, 7, 6, 5, 4, 3, 2]
[9, 8, 7, 6, 5, 4, 3, 2, 1]
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值