队列(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