zoukankan      html  css  js  c++  java
  • Python模拟 栈 队列 以及优先队列的操作记录

    栈:数据是后进先出 (LIFO)     last in first out

    队列:数据是先进先出 (FIFO)  first in first out

    第一种就是列表:(既可以模拟栈也可以模拟队列)一好一差。(还有一个缺点,不能通过简单的方式,设置容器容量的空间。)

    列表是一种容器序列,而且在模拟栈操作的时候,速度也是比较可以的。

    在模拟栈操作时,必须用append于pop。(模拟栈的时候,性能优秀)

    下面演示的是模拟队列操作,模拟栈操作很简单,就是append于pop所以不展示了。

    In [228]: ll = list()                                                                   
    
    In [229]: ll.append('任务1')                                                            
    
    In [230]: ll.append('任务2')                                                            
    
    In [231]: ll.append('任务3')                                                            
    
    In [232]: ll.pop(0)                                                                     
    Out[232]: '任务1'
    
    In [233]: ll.pop(0)                                                                     
    Out[233]: '任务2'
    
    In [234]: ll.pop(0)                                                                     
    Out[234]: '任务3'
    

     这样的模拟操作队列效率是非常低的,因为你每次移出第一个元素,后面的元素索引都会发生变化

    专业的说法需要的时间为O(n)

    第二个为collections.deque,这个一个模拟栈于队列都非常优秀的容器序列。(可以设置容器容量大小,当超过最大容量时,最先进去的元素将被踢出容器

    除了随机访问该对象中间的元素的性能很差,耗时为O(n),但一般操作容器序列,很少取访问中间元素。

    模拟栈操作:

     from collections import deque                                                  
    
    In [34]: deque?                                                                         
    Init signature: deque(self, /, *args, **kwargs)
    Docstring:     
    deque([iterable[, maxlen]]) --> deque object
    
    A list-like sequence optimized for data accesses near its endpoints.
    File:           /usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/collections/__init__.py
    Type:           type
    Subclasses:     
    
    In [35]: d = deque(range(10),maxlen=5)                                                  
    
    In [36]: d                                                                              
    Out[36]: deque([5, 6, 7, 8, 9])
    
    In [37]: d.append(10)                                                                   
    
    In [38]: d                                                                              
    Out[38]: deque([6, 7, 8, 9, 10])
    
    In [39]: d.pop()                                                                        
    Out[39]: 10
    
    In [40]: d.pop()                                                                        
    Out[40]: 9
    
    In [41]: d.pop()                                                                        
    Out[41]: 8
    
    In [42]: d.pop()                                                                        
    Out[42]: 7
    
    In [43]: d.pop()                                                                        
    Out[43]: 6
    
    In [44]: d.pop()                                                                        
    ---------------------------------------------------------------------------
    IndexError                                Traceback (most recent call last)
    <ipython-input-44-663961784a31> in <module>
    ----> 1 d.pop()
    
    IndexError: pop from an empty deque
    

     模拟队列操作:

     d                                                                              
    Out[45]: deque([])
    
    In [46]: d.append(1)                                                                    
    
    In [47]: d.append(2)                                                                    
    
    In [48]: d.append(3)                                                                    
    
    In [49]: a                                                                              
    ---------------------------------------------------------------------------
    NameError                                 Traceback (most recent call last)
    <ipython-input-49-3f786850e387> in <module>
    ----> 1 a
    
    NameError: name 'a' is not defined
    
    In [50]: d                                                                              
    Out[50]: deque([1, 2, 3])
    
    In [51]: d.popleft()                                                                    
    Out[51]: 1
    
    In [52]: d.popleft()                                                                    
    Out[52]: 2
    
    In [53]: d.popleft()                                                                    
    Out[53]: 3
    

    上面两个是即可以模拟栈,又可以模拟队列的容器序列,下面介绍的是只能单一模拟栈或者队列的。

    queue.LifoQueue从字面就可以看出来是模拟栈的,后进先出。queue模块下的容器序列,提供了锁语句来支持多个并发的生产者于消费者。模块下面的很多类的实例一般用在线程间的通讯。

    因为这个容器在取不到元素或者元素的数量超过设置容量时,会阻塞程序。(所以很明显这个是可以设置容量的)

    In [54]: from queue import LifoQueue                                                    
    
    In [55]: LifoQueue?                                                                     
    Init signature: LifoQueue(maxsize=0)
    Docstring:      Variant of Queue that retrieves most recently added entries first.
    File:           /usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/queue.py
    Type:           type
    Subclasses:     
    
    In [56]: q = LifoQueue()                                                                
    
    In [57]: q = LifoQueue(maxsize=3)                                                       
    
    In [58]: q.put(1)                                                                       
    
    In [59]: q.put(2)                                                                       
    
    In [60]: q.put(3)                                                                       
    
    In [61]: q.get()                                                                        
    Out[61]: 3
    
    In [62]: q.get()                                                                        
    Out[62]: 2
    
    In [63]: q.get()                                                                        
    Out[63]: 1
    
    In [64]: q.get()    
    阻塞
    

    栈的我了解的就是上面三种形式,一般优先使用collections.queue

    后面的单一功能主要队列的序列容器。

    queuq.Queue跟前面的LifoQueue功能于操作都差不多,而且都是用线程之间的任务通讯操作。

    In [94]: q = Queue(maxsize=3)                                                           
    
    In [95]: q.put(1)                                                                       
    
    In [96]: q.put(2)                                                                       
    
    In [97]: q.put(3)                                                                       
    
    In [98]: q.get()                                                                        
    Out[98]: 1
    
    In [99]: q.get()                                                                        
    Out[99]: 2
    
    In [100]: q.get()                                                                       
    Out[100]: 3
    
    In [101]: q.get()    
    阻塞

    最后还有一个multiprocessing.Queue进行作业队列。

    multiprocessing.Queue主要是进程间进行作业通讯的工具,具体使用基本于

    queue.Queue差不多,就不上代码了。

    最后简单的记录一下优先队列。

    优先队列史一个容器数据结构,使用具有全序关系的键来管理元素,以便快速访问容器中键值最小或者最大的元素。

    1、列表,手动维护有序队列。

    In [102]: q = []                                                                        
    
    In [103]: q.append((2, 'code'))                                                         
    
    In [104]: q.append((1,'eat'))                                                           
    
    In [105]: q.append((3,'sleep'))                                                         
    
    In [106]: q.sort(reverse=True)                                                          
    
    In [107]: q.pop()                                                                       
    Out[107]: (1, 'eat')
    
    In [108]: q.pop()                                                                       
    Out[108]: (2, 'code')
    
    In [109]: q.pop()                                                                       
    Out[109]: (3, 'sleep')
    
    In [110]: import bisect                                                                 
    
    In [111]: bisect.insort(q,(2, 'code'))                                                  
    
    In [112]: bisect.insort(q,(1, 'eat'))                                                   
    
    In [113]: bisect.insort(q,(3, 'sleep'))                                                 
    
    In [114]: q                                                                             
    Out[114]: [(1, 'eat'), (2, 'code'), (3, 'sleep')]
    
    In [115]:  
    

     bisect在已经排序完成的情况下,查寻索引非常快的,bisect.bisect可以查寻索引。比默认的.index快太多了。

    heapq--基于列表的二叉堆。

    heaqp是二叉堆,通常用普通列表实现,能在O(logn)时间内插入和获取最小的元素。

    heapq模块是在Python中不错的优先级队列实现。由于heapq的技术上只提供最小堆实现,因此必须添加额外步骤来确保排序的稳定性,以此来获得实际的优先级队列中所含有的特性。

    In [140]:  
         ...: q =  [(2, 'code'), (3, 'sleep'), (1, 'eat'), (4,'drink')] 
         ...:                                                                               
    
    In [141]: random.shuffle(q)                                                             
    
    In [142]: h_q = []                                                                      
    
    In [143]: for i in q: 
         ...:     heapq.heappush(h_q, i) 
         ...:                                                                               
    
    In [144]: heapq.heappop(h_q)                                                            
    Out[144]: (1, 'eat')
    
    In [145]: heapq.heappop(h_q)                                                            
    Out[145]: (2, 'code')
    
    In [146]: heapq.heappop(h_q)                                                            
    Out[146]: (3, 'sleep')
    
    In [147]: heapq.heappop(h_q)                                                            
    Out[147]: (4, 'drink')
    
    In [148]: q =  [(2, 'code'), (3, 'sleep'), (1, 'eat'), (4,'drink')]                     
    
    In [149]: random.shuffle(q)                                                             
    
    In [150]: heapq.heapify(q)                                                              
    
    In [151]: heapq.heappop(q)                                                              
    Out[151]: (1, 'eat')
    
    In [152]: heapq.heappop(q)                                                              
    Out[152]: (2, 'code')
    
    In [153]: heapq.heappop(q)                                                              
    Out[153]: (3, 'sleep')
    
    In [154]: heapq.heappop(q)                                                              
    Out[154]: (4, 'drink')
    

     上面用了heapq的两种方式堆列表进行了二叉堆操作。第一种是变量元素用heapq.heappush进行数据加载,第二种直接用heapq.heapify对列表元素实行二叉堆。

    heapq.nlargest,heapq.nsmallest可以找出容器元素内的最大值范围于最小值范围,通过key=函数,传递函数。

    from queue import PriorityQueue                                               
    
    In [163]: PriorityQueue?                                                                
    Init signature: PriorityQueue(maxsize=0)
    Docstring:     
    Variant of Queue that retrieves open entries in priority order (lowest first).
    
    Entries are typically tuples of the form:  (priority number, data).
    File:           /usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/queue.py
    Type:           type
    Subclasses:     
    
    In [164]: q =  [(2, 'code'), (3, 'sleep'), (1, 'eat'), (4,'drink')]                     
    
    In [165]: p_q = PriorityQueue()                                                         
    
    In [166]: for i in q: 
         ...:     p_q.put(i) 
         ...:                                                                               
    
    
    In [171]: p_q.empty                                                                     
    Out[171]: <bound method Queue.empty of <queue.PriorityQueue object at 0x10b5e2b90>>
    
    In [172]: p_q.empty()                                                                   
    Out[172]: False
    
    In [173]: while not p_q.empty(): 
         ...:     print(p_q.get()) 
         ...:      
         ...:                                                                               
    (1, 'eat')
    (2, 'code')
    (3, 'sleep')
    (4, 'drink')
    
    In [174]:                                                                               
    

     queue.PriorityQueue内部也是使用了heapq,时间复杂度于空间复杂度于heapq相同,但PriorityQueue队列执行并发生产者消费者。可以在特定条件下阻塞。

     queue.PriorityQueue可以给nametuple对象进行优先级压入弹出,弹出参数按照nametuple对象第0个元素的值从小到大进行弹出,本质上来说,nametuple就是元祖。

    In [23]: from queue import PriorityQueue                                                                        
    
    In [24]: q = PriorityQueue()                                                                                    
    
    In [25]: car = namedtuple('car','number,colour')                                                                
    
    In [26]: car1 = car(3,'red')                                                                                    
    
    In [27]: car2 = car(1,'yellow')                                                                                 
    
    In [28]: car3 = car(2,'gren')                                                                                   
    
    In [29]: q.put(car1)                                                                                            
    
    In [30]: q.put(car2)                                                                                            
    
    In [31]: q.put(car3)                                                                                            
    
    In [32]: q.get()                                                                                                
    Out[32]: car(number=1, colour='yellow')
    
    In [33]: q.get()                                                                                                
    Out[33]: car(number=2, colour='gren')
    
    In [34]: q.get()                                                                                                
    Out[34]: car(number=3, colour='red')
    
    In [35]: q.get()                                                                                                
    

    queue里面的三个模块基本在模拟队列,栈,于优先级队列中都又使用。

    分别是queue.LifoQueue,queue.Queue,queue.PriorityQueue。

    Python前面记录的三种优先队列,其中priorityQueue是其中的首选,具有良好的面向对象的接口

    如果想避免PriorityQueue的锁开销,建议直接用heapq模块。

  • 相关阅读:
    在IDEA通过Maven构建Scala项目
    6.Pair RDD操作
    5.RDD的Action操作和持久化persist()
    29.Spark SQL发展史
    AirFlow初始化的时候遇到 Global variable explicit_defaults_for_timestamp needs to be on (1) for mysql
    4.RDD操作之Transform
    3.RDD详解和创建RDD方式
    28.Spark中action的介绍
    2.Spark 2.x 集群部署和测试
    Repeater分页
  • 原文地址:https://www.cnblogs.com/sidianok/p/12071123.html
Copyright © 2011-2022 走看看