文章目录
队列
什么是队列?
队列(Queue)是一种常见的数据结构,它遵循先进先出(First-In-First-Out,FIFO)的原则。简单来说,队列就像是一个排队等候的人群,新的元素被添加到队列的末尾,而从队列中移除元素时,总是从队列的前端进行。
队列的特点
- 队尾入队
- 队首出队
两种线性表结构实现队列(附件中均附有源码)
队列实现的操作
python顺序表实现队列
创建一个空的队列
class Queue:
def __init__(self):
self.item = []
判断队列是否为空和返回元素个数
class Queue:
def __init__(self):
self.item = []
def is_empty(self):
return self.length() == 0
def length(self):
return len(self.item)
添加一个元素到队尾
因为是用顺序表结构实现队列,也就是列表,那么这里就要考虑将列表的第一个元素作为队首还是队尾
添加一个元素到队尾 用append方法,因为insert方法时间复杂度为O(n),而append方法的时间复杂度为O(1)
def push(self,data):
'''添加一个元素到队尾 用append方法,因为insert方法时间复杂度为O(n)'''
self.item.append(data)
弹出队头
将队头从队列中踢出,并返回队头元素
同样的,我们使用列表的pop方法来删除并返回指定的元素。
但是值得注意的是,pop方法在列表元素为空的时候(也就是找不到指定的索引元素的时候)会报错,这个时候我们手动抛出异常
def pop(self):
if self.is_empty():
raise ValueError('队列为空')
return self.item.pop(0)
获取队头
仅仅是返回队头元素,并不删除队头元素
def peek(self):
if self.is_empty():
raise ValueError('队列为空')
return self.item[0]
pyhton链式表实现队列
简单操作如下
class Node():
def __init__(self,data,next = None):
self.data = data
self.next = next
class Queue:
'''
链表的第一个元素是队列的头部,链表的最后一个元素是对列的尾部
'''
def __init__(self):
self.head = None
self.rear = None
self.lenth = 0
def is_empty(self):
return self.lenth == 0
def length(self):
return self.lenth
添加一个元素data到队列尾部
- 创建一个新的结点
- 将新的结点添加到链表的尾部(链表的尾部既队列的尾部)
- 将原来的尾结点的next属性指向新的结点
- 将队列的rear(原来的尾结点)属性指向新的结点
- 队列长度加1
- 特殊情况下:
如果链表为空
那么就是添加到链表的头部 具体操作如下:
1.将队列的head属性指向新的结点
2.将队列的rear属性指向新的结点 (因为在空的队列中台添加一个对象那么这个对象既是队首又是队尾)
def push(self,data):
node = Node(data) # 创建一个新的结点
if self.is_empty(): #特殊情况
self.head = node
self.rear = node
else:
self.rear.next = node # 将原来的尾结点的next属性指向新的结点
self.rear = node # 将队列的rear(原来的尾结点)属性指向新的结点
self.lenth += 1
抛出队首元素
原版代码(原版代码没有错,只是有点漏洞,但是不会影响程序的正常运行)
队首元素也就是链表的第一个结点
- 创建一个变量指向头节点(用于后续的返回)
- 将链表的head属性指向原来头节点的下一个结点
def pop(self):
if self.is_empty():
raise ValueError('队列为空')
value = self.head.data
self.head = self.head.next
# print(f'队列的头部结点是{self.rear.data}')
self.lenth -= 1
return value
这里我们来思考一种特殊的情况====>>>
当链表中只有一个元素的时候,head属性和rear属性指向的都是第一节点,那么这个时候执行pop方法的时候头节点指向下一个结点(self.head = self.head.next),但是尾结点呢?我们并没有用代码改正尾结点的指向,是不是尾结点还是指向原来的头结点(也就是被我们删掉的那个结点)?是不是我们是使用self.rear.data能够直接访问到被删除结点的值?
我们做个实验验证以下,将上述代码的第六行解除注释运行以下试试看
'''
运行代码如下
'''
if __name__ == '__main__':
queue = Queue()
queue.push(1)
print(queue.pop())
print(f'队列的头部结点是{queue.rear.data}')
运行结果如图所示
可见在外部和内部进行访问的时候访问到的都是原来的值,其rear并未指向None。
改进代码如下:
def pop(self):
'''抛出队首元素也就是链表的第一个结点'''
'''
创建一个变量指向头节点(用于后续的返回)
将链表的head属性指向原来头节点的下一个结点
'''
if self.is_empty():
raise ValueError('队列为空')
value = self.head.data
if self.lenth == 1:
self.head = None
self.rear = None
# print(f'队列的头部结点是{self.rear}')
else:
self.head = self.head.next
self.lenth -= 1
return value
返回队首元素
返回头节点的值即可
def peek(self):
if self.is_empty():
raise ValueError('队列为空')
return self.head.data
附件
附件1:顺序表实现队列的完整代码
# @Author :泰敢人辣
# Date :2023-07-29 17:46
'''用python实现队列'''
class Queue:
def __init__(self):
self.item = []
def is_empty(self):
return self.length() == 0
def length(self):
return len(self.item)
def push(self,data):
'''添加一个元素到队尾 用append方法,因为insert方法时间复杂度为O(n)'''
self.item.append(data)
def pop(self):
if self.is_empty():
raise ValueError('队列为空')
return self.item.pop(0)
def peek(self):
if self.is_empty():
raise ValueError('队列为空')
return self.item[0]
if __name__ == '__main__':
queue = Queue()
queue.pop()
附件2:链表实现队列的完整代码
# @Author :泰敢人辣
# Date :2023-07-29 18:17
'''用链表实现队列'''
# 定义结点类
class Node():
def __init__(self,data,next = None):
self.data = data
self.next = next
class Queue:
'''
链表的第一个元素是队列的头部,链表的最后一个元素是对列的尾部
'''
def __init__(self):
self.head = None
self.rear = None
self.lenth = 0
def is_empty(self):
return self.lenth == 0
def length(self):
return self.lenth
def push(self,data):
'''
添加一个元素data到队列尾部
创建一个新的结点
将新的结点添加到链表的尾部(链表的尾部既队列的尾部)
将原来的尾结点的next属性指向新的结点
将队列的rear(原来的尾结点)属性指向新的结点
队列长度加1
特殊情况下:
如果链表为空
那么就是添加到链表的头部 具体操作如下:
1.将队列的head属性指向新的结点
2.将队列的rear属性指向新的结点 (因为在空的队列中台添加一个对象那么这个对象既是队首又是队尾)
'''
node = Node(data)
if self.is_empty():
self.head = node
self.rear = node
else:
self.rear.next = node # 将原来的尾结点的next属性指向新的结点
self.rear = node # 将队列的rear(原来的尾结点)属性指向新的结点
self.lenth += 1
def pop(self):
'''抛出队首元素也就是链表的第一个结点'''
'''
创建一个变量指向头节点(用于后续的返回)
将链表的head属性指向原来头节点的下一个结点
'''
if self.is_empty():
raise ValueError('队列为空')
value = self.head.data
if self.lenth == 1:
self.head = None
self.rear = None
# print(f'队列的头部结点是{self.rear}')
else:
self.head = self.head.next
self.lenth -= 1
return value
def peek(self):
if self.is_empty():
raise ValueError('队列为空')
return self.head.data
if __name__ == '__main__':
queue = Queue()
queue.push(1)
queue.push(2)
queue.push(3)
queue.push(4)
print(queue.peek())
print(queue.pop())
print(queue.pop())
print(queue.pop())
print(queue.pop())