数据结构笔记2

来自《Python数据结构学习笔记》(张清云  编著)

第五章 队列和栈

5.1队列

5.1.1

主要作用:
  • 解耦,使程序实现松耦合(一个模块修改不会影响其他模块)
  • 提高程序的效率
循环队的入队算法:
  1. tail=tail+1
  2. 如果tail=n+1,则tail=1
  3. 如果head=tail,尾指针和头指针重合,表示元素已装满队列,实行“上溢”出错处理;否则Q(tail)=X,结束整个过程,X表示新的出入元素。
队列的基本操作:
(1)InitQueue(&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()失败,则操作失败

5.1.2 Python内置的队列操作方法

  • Queue():定义一个空队列。无参数,返回值是空队列
  • enqueue(item):在队列尾部加入一个数据项。参数是数据项,无返回值
  • dequeue():删除队列头部的数据项。不需要参数,返回值是被删除的数据,队列本身有变化

5.1.3  基于内置模块queue的队列

(1)FIFO(先进先出)

import queue
q=queue.Queue()
q.put(1)
q.put(2)
q.put(3)

print(q.get())
print(q.get())
print(q.get())
1
2
3

(2)LIFO(后进先出)

import queue
q=queue.LifoQueue()
q.put(1)
q.put(2)
q.put(3)

print(q.get())
print(q.get())
print(q.get())
3
2
1

(3)数据可设置优先级

import queue

q=queue.PriorityQueue()
q.put((2,'2'))
q.put((1,'1'))
q.put((3,'3'))
q.put((1,'a'))

print(q.get())
print(q.get())
print(q.get())
print(q.get())
(1,'1')
(1,'a')
(2,'2')
(3,'3')

(4)向任务已经完成的队列发送一个信号

当t2线程将队列中的数据全部取出之后,才继续执行主线程。

import queue
import threading
import time

def q_put():
    for i in range(10):
        q.put('1')
    while True:
        q.put('2')
        time.sleep(1)

def q_get():
    while True:
        temp=q.get()
        q.task_done()        #告知等待的队列(queue.join())在这等待任务处理已完成
        print(temp)
        time.sleep(0.3)

q=queue.Queue()
t1=threading.Thread(target=q_put)
t2=threading.Thread(target=q_get)
t1.start()
t2.start()
q.join()        #开始阻塞
print('queue is empty now')

(5)生产者和消费者模型

通过一个容器解决生产者和消费者的强耦合问题。

生产者和消费者彼此不直接通信,通过阻塞队列来进行通信,阻塞队列相当于缓冲区,平衡生产者和消费者的处理能力。

import threading
import time
import queue

def producer():
    count=1
    while 1:
        q.put('No.%1' % count)
        print('Producer put No.%1' % count)
        time.sleep(1)
        count+=1

def customer(name):
    while 1:
        print('%s get %s' % (name,q.get())
        time.sleep(1.5)

q=queue.Queue(maxsize=5)
p=threading.Thread(target=producer,)
c=threading.Thread(target=customer,args=('jack',))
p.start()
c.start()

(6)完整的顺序队列的操作

from queue import Queue            #LILO队列
q=Queue()                          #创建队列对象
q.put(0)                           #在队列尾部插入元素
q.put(1)
q.put(2)
print('LILO队列',q.queue)          #查看队列中的所有元素
print(q.get())                    #返回并删除队列头部元素
print(q.queue)

from queue import LifoQueue        #LIFO队列
lifoQueue=LifoQueue()
lifoQueue.put(1)
lifoQueue.put(2)
lifoQueue.put(3)
print('LIFO队列',lifoQueue.queue)
lifoQueue.get()                    #返回并删除队列尾部元素
lifoQueue.get()
print(lifoQueue.queue)        

from queue import PriorityQueue      #优先队列
priorityQueue=PriorityQueue()        #创建优先队列对象
priorityQueue.put(3)                 #插入元素
priorityQueue.put(78)                #插入元素
priorityQueue.put(100)               #插入元素
print(priorityQueue.queue)           #查看优先级队列中的所有元素
priorityQueue.put(1)                 #插入元素
priorityQueue.put(2)                 #插入元素
print('优先级队列:',priorityQueue.queue)        #查看优先级队列中的所有元素
priorityQueue.get()                             #返回并删除优先级最低的元素 
print('删除后剩余元素',priorityQueue.queue)      
priorityQueue.get()                             #返回并删除优先级最低的元素
print('删除后剩余元素',priorityQueue.queue)      #删除后剩余元素
priorityQueue.get()                             #返回并删除优先级最低的元素
print('删除后剩余元素',priorityQueue.queue)      #删除后剩余元素
priorityQueue.get()                             #返回并删除优先级最低的元素
print('删除后剩余元素',priorityQueue.queue)      #删除后剩余元素
priorityQueue.get()                             #返回并删除优先级最低的元素
print('全部被删除后:',priorityQueue.queue)      #查看优先级队列中的所有元素

from collections import deque                   #双端队列
dequeQueue=deque(['Eric','John','Smith'])
print(dequeQueue)
dequeQueue.append('Tom')                        #在右侧插入新元素
dequeQueue.appendleft('Terry')                  #在左侧插入新元素
print(dequeQueue)
dequeQueue.rotate(2)                            #循环右移两次
print('循环右移两次后的队列',dequeQueue)
dequeQueue.popleft()                            #返回并删除队列最左端元素
print('删除最左端元素后的队列:',dequeQueue)
dequeQueue.pop()                                #返回并删除队列最右端元素
print('删除最右端元素后的队列:',dequeQueue)

5.1.4  基于列表自定义实现的优先队列

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 ListPriQueueError("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)

输出:

[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]

一些功能:

class Queue(object):

    def __init__(self):
        self._item=[]

    def is_empty(self):
        """判断队列是否为空"""
        return self.__item==[]

    def in_queue(self,item):
        """进队"""
        self.__item.append(item)

    def out_queue(self):
        """出队"""
        return self.__item.pop(0)

    def size(self):
        """返回大小"""
        return self.__item.__len__()

if __name__=='__main__':
    q=Queue()
    print(q.is_empty())

    q.in_queue(1)
    q.in_queue(2)
    q.in_queue(3)
    q.in_queue(4)
    print(q.is_empty())
    print(q.size())
    print(q.out_queue())
    print(q.out_queue())
    print(q.size())

输出:

True
False
4
1
2
2

5.1.5  基于堆实现的优先队列

首先判断要操作对象是否为空,然后将新的优先级加入到队列的末尾,将堆顶值最小优先级最高的元素出队,确保在弹出元素后仍然维持堆的顺序,并将最后的元素放在堆顶。

class Heap_Pri_Queue(object):
    def __init__(self,elems=[]):
        self._elems=list(elems)
        if self._elems:
            self.buildheap()

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

    #查看堆顶元素,即优先级最低元素
    def peek(self):
        if self.is_empty():
            raise HeapPriQueueError("in pop")
        return self._elems[0]

    #将新的优先级加入队列O(logn)
    def enqueue(self,e):
        #在队列末尾创建一个空元素
        self._elems.append(None)
        self.siftup(e,len(self._elems)-1)

    #新的优先级默认放在末尾,因此失去堆序,进行siftup构建堆序
    #将e位移到正确的位置
    def siftup(self,e,last):
        elems,i,j=self._elems,last,(last-1)//2    #j为i的父节点
        while i>0 and e<elems[j]:
            elems[i]=elems[j]
            i,j=j,(j-1)//2
        elems[i]=e

    #堆顶值最小优先级最高的出队,确保弹出元素后仍然维持秩序
    #将最后的元素放在堆顶,然后进行siftdown
    #O(logn)
    def dequeue(self):
        if self.is_empty():
            raise HeapPriQueueError("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
        while i<end:
            if j+1<end and elems[j]>elems[j+1]:
                j+=1
            if e<elems[j]:
                break
            elems[i]=elems[j]
            i,j=j,j*2+1
        elems[i]=e

    #构建堆序 O(n)
    def buildheap(self):
        end=len(self._elems)
        for i in range(end//2,-1,-1):
            self.siftdown(self._elems[i],i,end)

if __name__=="__main__":
    l=Heap_Pri_Queue([5,6,1,2,4,8,9,0,3,7])
    print(l._elems)
    #[0,2,1,3,4,8,9,6,5,7]
    l.dequeue()
    print(l._elems)
    #[1,2,7,3,4,8,9,6,5,7]
    print(l.is_empty())
    l.queue(0)
    print(l._elems)
    print(l.peak())

输出:

[0,2,1,3,4,8,9,6,5,7]
[1,2,7,3,4,8,9,6,5]
False
[0,1,7,3,2,8,9,6,5,4]
0

5.1.6  双端队列

class Deque:
    """双端队列"""
    def __init__(self):
        self.items=[]

    def add_front(self,item):
        """从队头加入一个元素"""
        self.items.insert(0,item)

    def add_rear(self,item):
        """从队尾加入一个元素"""
        self.items.append(item)
    
    def remove_front(self):
        """从队头删除一个元素"""
        return self.item.pop(0)

    def remove_rear(self):
        """从队尾删除一个元素"""
        return self.items.pop()

    def is_empty(self):
        """是否为空"""
        return self.items==[]

    def size(self):
        """队列长度"""
        return len(self.items)

if __name__=="__main__":
    deque=Deque
    deque.add_front(1)
    deque.add_front(2)
    deque.add_rear(3)
    deque.add_rear(4)
    print(deque.size())            #4
    print(deque.remove_front())    #2
    print(deque.remove_front())    #1
    print(deque.remove_fear())     #4
    print(deque.remove_fear())     #3

输出:

4
2
1
4
3

  • 13
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值