队列的定义
队列(queue)是只允许在一端进行拆入操作,而在另一端进行删除操作的线性表。队列是一种先进先出(First In First Out)的线性表,简称FIFO。允许插入的一段称为队尾,允许删除的一端称为队头。
队列的应用非常频繁,例如排队,键盘输入到显示器输出等。
队列的抽象数据类型
ADT 队列(Queue) Data '''同线性表。元素具有相同的类型,相邻元素具有前驱和后继关系。''' Operation InitQueue(*Q):'''初始化操作,建立一个空队列Q。''' DestroyQueue(*Q):'''若队列Q存在,则销毁它''' ClearQueue(*Q):'''将队列Q清空''' QueueEmpty(Q):'''若队列Q为空,返回true,否则返回false''' GetHead(Q,*e):'''若队列Q存在且非空,用e返回Q的队头元素。''' EnQueue(*Q,e):'''若队列Q存在,插入新元素e插入到Q中并成为队尾元素。''' DeQueue(*Q,*e):'''删除队列Q中队头元素,并用e返回其值。''' QueueLength(Q):'''返回队列Q的元素个数。''' endADT
循环队列
当用线性表表示队列时,为了避免队列元素的大量移动(队头删除元素时),一般引入两个指针,front指向队头元素,rear指向队尾元素的下一个位置,这样,拆入始终在rear指针处进行,删除始终在front指针处进行;当front等于rear时,此队列为空队列。但是这样会产生另外一个问题,列队经过一些拆入和删除操作之后,rear指针可能发生数值越界,但数值的另一端还有空闲,这种现象叫做假溢出。
解决假溢出的办法就是后面满了,再从头开始,也就是头尾相接的循环。我们把队列的这种头尾相接的顺序存储结构称为循环队列。如下图所示
此时会产生另外一个问题,当rear=front时,有可能表示队满,也可能表示队空,为了区分这种情况有两种解决方案
- 多设置一个flag变量,当rear=front,且flag=0时,表示队列空。当rear=front,且flag=1时表示队满
- 让队列始终保留一个空元素,也就是,当rear=front时,队列空。当队列仅剩一个空闲元素时,队列慢,所以以下两种情况都表示队列满
循环队列的Python实现
class SqQueue(object): def __init__(self,size=20): self.data=[None for i in range(size)] self.size=size self.front=0 self.rear=0
循环队列的插入操作
def EnQueue(self,e):#将e插入队列 if (self.rear+1)%self.size ==self.front: #队列满 return 0 self.data[self.rear]=e #当前元素赋值给e self.rear=(self.rear+1)%self.size #rear指向下一个 return 1
循环队列的删除操作
def DeQueue(self): if self.rear==self.front: #队空 return None e=self.data[self.front] #获取队头元素 self.data[self.front]=None #删除队头元素 self.front=(self.front+1)%self.front #头指针往前移动一位 return e
循环队列的完整代码
class SqQueue(object): def __init__(self,size=20): self.data=[None for i in range(size)] self.size=size self.front=0 self.rear=0 def QueueLength(self): #返回队列的长度 return (self.rear-self.front+self.size)%self.size def EnQueue(self,e):#将e插入队列 if (self.rear+1)%self.size ==self.front: #队列满 return 0 self.data[self.rear]=e #当前元素赋值给e self.rear=(self.rear+1)%self.size #rear指向下一个 return 1 def DeQueue(self): if self.rear==self.front: #队空 return None e=self.data[self.front] #获取队头元素 self.data[self.front]=None #删除队头元素 self.front=(self.front+1)%self.front #头指针往前移动一位 return e def ClearQueue(*Q):#将队列清空 while self.front!=self.rear: #当队列不空时 self.data[self.front]=None #删除对头元素,队头前移一位 self.front=(self.front+1)%self.size def QueueEmpty(self):#若队列Q为空,返回true,否则返回false return self.front==self.rear def GetHead(self): #若队列Q存在且非空,用e返回Q的队头元素 return self.data[self.front] #返回当前元素,若队列为空,返回None
队列的链式存储结构及实现
队列的链式存储结构,其实就是线性表的单链表,只不过它只能尾进头出,我们把它简称连队列。
当front和rear都指向头结点时,表示连队列为空。
链队列的实现代码如下:
class LinkQueue(object): def __init__(self): #生成一个空的链队列 self.front=Node(0) #头节点,保存元素的个数 self.rear=self.front def QueueLength(self): #返回队列的长度 return self.count
队列的链式存储结构——入队操作
def EnQueue(self,e): #将e插入队列 p=Node(e) #待拆入节点 self.rear.next=p #尾节点下一个节点指向p self.rear=p #尾指针移到p self.front.data+=1 #节点个数+1
队列的链式存储结构——出队操作
def DeQueue(self): if self.rear==self.front:return None #如果链表为空 p=self.front.next #待删除 e=p.data self.front.next=p.next #头结点的下一个节点直接指向p的下个节点 if self.rear==p: #如果删除的是尾节点 self.rear=self.front #维指针指向头节点 self.front.data-=1 return e
链队列的完整代码
class Node(object): #定义链表节点 def __init__(self,data=None): self.data=data self.next=None class LinkQueue(object): def __init__(self): #生成一个空的链队列 self.front=Node(0) #头节点,保存元素的个数 self.rear=self.front def QueueLength(self): #返回队列的长度 return self.count def EnQueue(self,e): #将e插入队列 p=Node(e) #待拆入节点 self.rear.next=p #尾节点下一个节点指向p self.rear=p #尾指针移到p self.front.data+=1 #节点个数+1 def DeQueue(self): if self.rear==self.front:return None #如果链表为空 p=self.front.next #待删除 e=p.data self.front.next=p.next #头结点的下一个节点直接指向p的下个节点 if self.rear==p: #如果删除的是尾节点 self.rear=self.front #维指针指向头节点 self.front.data-=1 return e def ClearQueue(*Q):#将队列清空 self.front=Node(0) self.rear=self.front def QueueEmpty(self):#若队列Q为空,返回true,否则返回false return self.front==self.rear def GetHead(self): #若队列Q存在且非空,用e返回Q的队头元素 if self.front.next==None:return None else: return self.front.next.data