Python队列

队列(Queue)

概念:

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。核心概念是先进先出

分类:

队列本身也是一种线性表,因而和线性表一样也有顺序和链式存储结构两种存储方式。

  • 采用顺序存储结构实现的队列称为顺序队列
  • 采用链式存储结构实现的队列称为链队列。
基本属性:

一. 队首(front)
删除数据的一端。对于数组,从后面插入更容易,前面插入较困难,所以一般用数组实现的队列队头在前面。(删除直接index游标前进,不超过队尾即可)。而对于链表。插入删除在两头分别进行那么头部(前面)删除尾部插入是最方便的选择。

二. 队尾(rear)
插入数据的一端,同上,在数组和链表中通常均在尾部位置

三. 入队(enQueue)
在队尾rear插入元素

四. 出队(deQueue)
在对头front删除元素

普通队列

一. 图解
在这里插入图片描述
问题:每个空间区域只能利用一次。造成空间极度浪费。并且容易越界
在这里插入图片描述

二. Python实现
使用Python的内建类型list列表

#!/usr/bin/env python
# -*- coding: utf-8 -*-

class Queue:
    def __init__(self):
        self.items = []

    def enqueue(self, item):
        self.items.append(item)

    def dequeue(self):
        return self.items.pop(0)

    def empty(self):
        return self.size() == 0

    def size(self):
        return len(self.items)

使用python的链表实现链队

class Node:
	'''节点类'''
	def __init__(self,value):
		self.value = value
		self.next = None

class Queue:
	def __init__(self,node=None):
		'''空队列,记录队头位置'''
		self.head = node
	
	def is_empty(self):
		'''判断队列是否为空'''
		if self.head is None:
			return True
		return False
	
	def enqueue(self,val):
		'''入队列:在链表的尾部添加一个节点'''
		node = Node(val)
		#当是空链表时
		if self.is_empty():
			self.head = node
		#不是空链表
		else:
			current = self.head
			#循环完,current一定移动到尾巴节点
			while current.next:
				current = current.next
			
			current.next = node	#尾巴节点的next指向新节点
			node.next = Node	#新节点指向空
	
	def dequeue(self):
		'''出队列:相当于删除头结点,指针head指向head.next就行了'''
		if self.is_empty():
			raise Exception('queue is empty')
		result = self.head.value
		self.head = self.head.next	#这里head能是有node节点的next,value属性,是因为她先调用了enqueue()
		return result
	
	def top(self):
		'''查看队头元素:查看self.head的值'''
		if self.is_empty():
			raisr Exception('queue is empty')
		return self.head.value
	
	def travel(self):
		'''遍历整个队列:从队头 -> 队尾 输出'''
		if self.is_empty():
			return 
		else:
			current = self.head
			while current is not None:
				print(current.value,end=" ")
				current = curent.next
				print()	#换行
循环队列

针对普通队列容易造成空间浪费的问题,循环队列能队申请的内存空间重复利用

  • 初始化:数组的front和rear都指向0.
  • 入队:队不满,先队尾位置传值,再rear=(rear + 1) % maxsize;
  • 出队:队不空,先取队头位置元素,front=(front + 1)%maxsize;
  • 是否为空:return rear == front;
  • 大小:return (rear+maxsize-front)%maxsize;

一. 图解
在这里插入图片描述
二. Python实现

class LoopQueue(object):
    """
    循环队列:
    1. 队列是先进先出的线性结构,队列是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。允许插入的一端称为队尾,允许删除的一端称为队头
    2. 循环队列包括两个指针, front 指针指向队头元素, rear 指针指向队尾元素的下一个位置。
    3. 队列为空的判断条件是: front == rear
    4. 队列满的判断条件是: (rear+1)%maxsize == front
    5. 队列长度的计算公式:(rear-front+maxsize)%maxsize
    6. 入队时: rear = (rear + 1) % maxsize
    7. 出队时: front = (front + 1) % maxsize
    循环队列的优点:
    单向队列入队时间复杂度O(1),出队的时间复杂度为O(n) 因为出队为了维护队列的队首,后面的成员都需要向前移   循环队列的出队时间复杂队为O(1)
    而且对于出队后的元素,由于队列只能在队尾增加元素,所以前面出队的空出来的元素都浪费了空间
    """

    def __init__(self, maxsize=10):
        self.queue = [None] * (maxsize + 1)
        self.size = 0
        self.front = 0
        self.rear = 0

    def __str__(self):
        return str(self.queue)

    def __len__(self):
        return len(self.queue)

    def __iter__(self):
        return iter(self.queue)

    def get_size(self):
        """
        队列元素个数
        """
        return self.size

    def get_capaticty(self):
        return self.__len__() - 1

    def is_full(self):
        return (self.rear + 1) % len(self.queue) == self.front

    def is_empty(self):
        return self.rear == self.front

    def get_front(self):
        return self.queue[self.front]

    def inqueue(self, value):
        if self.is_full():
            self.resize(self.get_capaticty() * 2)
        self.queue[self.rear] = value
        self.rear = (self.rear + 1) % len(self.queue)
        self.size += 1

    def outqueue(self):
        if self.is_empty():
            raise Exception("The queue is empty")

        result = self.queue[self.front]
        self.queue[self.front] = None
        self.front = (self.front + 1) % len(self.queue)
        self.size -= 1

    def resize(self, new_capacity):
        new_queue = [None] * (new_capacity + 1)
        for i in range(self.size):
            new_queue[i] = self.queue[(i + self.front) % len(self.queue)]
        self.queue = new_queue
        self.front = 0
        self.rear = self.size
线程安全队列

python中的list不是线程全队列,因为例如list在append()或者remove()的时候,资源是共享的,然后python没有在这些队列里面封装锁。
线程安全,就是一个线程在同一时间只能被调用一次

Python的threading中定义了两种锁:threading.Lock和threading.RLock
两者的不同在于后者是可重入锁,也就是说在一个线程内重复LOCK同一个锁不会发生死锁
threading模块lock和Rlock的使用
threading模块Condition的使用

import threading


class ThreadSecurtyQueue(object):

    def __init__(self, maxsize=0):
        self.queue = []
        self.maxsize = maxsize
        # 定义线程锁
        self.mutex = threading.Lock()
        # 定义条件变量并传入锁 默认为Rlock
        self.cond = threading.Condition(self.mutex)

    def _get_size(self):
        """
        获取队列的元素个数
        :return:
        """
        return len(self.queue)

    def __str__(self):
        return str(self.queue)

    def qsize(self):
        """
        线程安全获取队列元素个数
        :return:
        """
        with self.cond:
            return self._get_size()

    def is_empty(self):
        """
        线程安全判断列表是否为空
        :return:
        """
        with self.cond:
            return not self._get_size()

    def is_full(self):
        """
        线程安全判断队列是否满
        :return:
        """
        with self.cond:
            return 0 < self.maxsize <= self._get_size()

    def put(self, value):
        """
        线程安全入队
        :param value:
        :return:
        """
        with self.cond:
            if self.maxsize > 0:
                while self._get_size() >= self.maxsize:
                    self.cond.wait()
            self.queue.append(value)
            self.cond.notify()

    def get(self):
        """
        线程安全出队
        :return:
        """
        with self.cond:
            while not self._get_size():
                self.cond.wait()
            item = self.queue.pop(0)
            self.cond.notify()
            return item
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值