设计循环队列
-
设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
-
循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。
-
你的实现应该支持如下操作:
MyCircularQueue(k): 构造器,设置队列长度为 k 。Front: 从队首获取元素。如果队列为空,返回 -1 。Rear: 获取队尾元素。如果队列为空,返回 -1 。enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。isEmpty(): 检查循环队列是否为空。isFull(): 检查循环队列是否已满。
示例:
MyCircularQueue circularQueue = new MyCircularQueue(3); // 设置长度为 3
circularQueue.enQueue(1); // 返回 true
circularQueue.enQueue(2); // 返回 true
circularQueue.enQueue(3); // 返回 true
circularQueue.enQueue(4); // 返回 false,队列已满
circularQueue.Rear(); // 返回 3
circularQueue.isFull(); // 返回 true
circularQueue.deQueue(); // 返回 true
circularQueue.enQueue(4); // 返回 true
circularQueue.Rear(); // 返回 4
提示:
- 所有的值都在 0 至 1000 的范围内;
- 操作数将在 1 至 1000 的范围内;
- 请不要使用内置的队列库。
Typescript 版算法实现
1 )方案 1: 基于数组
class MyCircularQueue {
// 属性初始化
list:number[]
front:number
rear:number
max:number
constructor(k: number) {
this.list = Array(k) // 初始化队列,长度为k
this.max = k // 队列的长度
this.front = 0 // 队首指针
this.rear = 0 // 队尾的指针
}
enQueue(value: number): boolean {
// 进入队列前检测当前是否已满,如果满了,则返回false
if (this.isFull()) return false
this.list[this.rear] = value
this.rear = (this.rear + 1) % this.max // 同步处理队尾下标,这样操作,会循环走,并且进一位
return true
}
deQueue(): boolean {
// 出队列前先检测是否为空, 如果为空,则返回 false
if (this.isEmpty()) return false
this.list[this.front] = null
this.front = (this.front + 1) % this.max // 同步处理队首下标
return true
}
Front(): number {
// 队首元素
if (this.isEmpty()) return -1
return this.list[this.front]
}
Rear(): number {
if (this.isEmpty()) return -1
const index = this.rear - 1
return this.list[index < 0 ? this.max - 1 : index]
}
isEmpty(): boolean {
// 队首和队尾的指针相同,并且队首元素为空,参考初始化的时候
return (this.front === this.rear) && !this.list[this.front]
}
isFull(): boolean {
// 队首和队尾的指针相同,并且队首元素有值
return this.front === this.rear && !!this.list[this.front]
}
}
/**
* Your MyCircularQueue object will be instantiated and called as such:
* var obj = new MyCircularQueue(k)
* var param_1 = obj.enQueue(value)
* var param_2 = obj.deQueue()
* var param_3 = obj.Front()
* var param_4 = obj.Rear()
* var param_5 = obj.isEmpty()
* var param_6 = obj.isFull()
*/
- 普通队列
- 是在队首删除,队尾增加
- 一个长度为k的队列,如果队尾是有元素的,再要求插入元素,即使在队列前面仍有空间也无法插入
- 循环队列
- 可以使用剩余的存储空间去存储新的值
- 不断修改尾部指针,指向前面被删除的空元素上
- 队列的应用场景在前端开发中非常多
- 比如监控和打点
- 我们可以依赖这样一个简单的队列的数据结构
- 加上处理进队,出队,队首,队尾的下标处理算法就可完成一个循环队列的创建
2 )方案2:基于链表
/*
// 注意,这个 ListNode 在 LeetCode 上是
class ListNode {
val: number;
next: ListNode | null;
constructor(val: number) {
this.val = val;
this.next = null;
}
}
*/
class MyCircularQueue {
private head: ListNode | null; // 链表的头节点,队列的头节点
private tail: ListNode | null; // 链表的尾节点,队列的尾节点
private capacity: number; // 队列的容量,即队列可以存储的最大元素数量
private size: number; // 队列当前的元素的数量
constructor(k: number) {
this.capacity = k;
this.size = 0;
this.head = this.tail = null;
}
enQueue(value: number): boolean {
if (this.isFull()) {
return false;
}
const node = new ListNode(value);
if (!this.head) {
this.head = this.tail = node;
} else {
this.tail!.next = node;
this.tail = node;
}
this.size++;
return true;
}
deQueue(): boolean {
if (this.isEmpty()) {
return false;
}
const node = this.head;
this.head = this.head!.next;
this.size--;
return true;
}
Front(): number {
return this.isEmpty() ? -1 : this.head!.val;
}
Rear(): number {
return this.isEmpty() ? -1 : this.tail!.val;
}
isEmpty(): boolean {
return this.size === 0;
}
isFull(): boolean {
return this.size === this.capacity;
}
}
/**
* Your MyCircularQueue object will be instantiated and called as such:
* var obj = new MyCircularQueue(k)
* var param_1 = obj.enQueue(value)
* var param_2 = obj.deQueue()
* var param_3 = obj.Front()
* var param_4 = obj.Rear()
* var param_5 = obj.isEmpty()
* var param_6 = obj.isFull()
*/
- 用链表实现队列,用链表实现队列则较为简单
- 因为链表可以在 O(1) 时间复杂度完成插入与删除
- 入队列时,将新的元素插入到链表的尾部;
- 出队列时,将链表的头节点返回,并将头节点指向下一个节点
Python3 版算法实现
1 )方案 1: 基于数组
class MyCircularQueue:
def __init__(self, k: int):
self.front = self.rear = 0
self.elements = [0] * (k + 1)
def enQueue(self, value: int) -> bool:
if self.isFull():
return False
self.elements[self.rear] = value
self.rear = (self.rear + 1) % len(self.elements)
return True
def deQueue(self) -> bool:
if self.isEmpty():
return False
self.front = (self.front + 1) % len(self.elements)
return True
def Front(self) -> int:
return -1 if self.isEmpty() else self.elements[self.front]
def Rear(self) -> int:
return -1 if self.isEmpty() else self.elements[(self.rear - 1) % len(self.elements)]
def isEmpty(self) -> bool:
return self.rear == self.front
def isFull(self) -> bool:
return (self.rear + 1) % len(self.elements) == self.front
# Your MyCircularQueue object will be instantiated and called as such:
# obj = MyCircularQueue(k)
# param_1 = obj.enQueue(value)
# param_2 = obj.deQueue()
# param_3 = obj.Front()
# param_4 = obj.Rear()
# param_5 = obj.isEmpty()
# param_6 = obj.isFull()
2 )方案2:基于链表
class MyCircularQueue:
def __init__(self, k: int):
self.head = self.tail = None
self.capacity = k
self.size = 0
def enQueue(self, value: int) -> bool:
if self.isFull():
return False
node = ListNode(value)
if self.head is None:
self.head = node
self.tail = node
else:
self.tail.next = node
self.tail = node
self.size += 1
return True
def deQueue(self) -> bool:
if self.isEmpty():
return False
self.head = self.head.next
self.size -= 1
return True
def Front(self) -> int:
return -1 if self.isEmpty() else self.head.val
def Rear(self) -> int:
return -1 if self.isEmpty() else self.tail.val
def isEmpty(self) -> bool:
return self.size == 0
def isFull(self) -> bool:
return self.size == self.capacity
# Your MyCircularQueue object will be instantiated and called as such:
# obj = MyCircularQueue(k)
# param_1 = obj.enQueue(value)
# param_2 = obj.deQueue()
# param_3 = obj.Front()
# param_4 = obj.Rear()
# param_5 = obj.isEmpty()
# param_6 = obj.isFull()
Golang 版算法实现
1 )方案 1: 基于数组
type MyCircularQueue struct {
front, rear int
elements []int
}
func Constructor(k int) MyCircularQueue {
return MyCircularQueue{elements: make([]int, k+1)}
}
func (q *MyCircularQueue) EnQueue(value int) bool {
if q.IsFull() {
return false
}
q.elements[q.rear] = value
q.rear = (q.rear + 1) % len(q.elements)
return true
}
func (q *MyCircularQueue) DeQueue() bool {
if q.IsEmpty() {
return false
}
q.front = (q.front + 1) % len(q.elements)
return true
}
func (q MyCircularQueue) Front() int {
if q.IsEmpty() {
return -1
}
return q.elements[q.front]
}
func (q MyCircularQueue) Rear() int {
if q.IsEmpty() {
return -1
}
return q.elements[(q.rear-1+len(q.elements))%len(q.elements)]
}
func (q MyCircularQueue) IsEmpty() bool {
return q.rear == q.front
}
func (q MyCircularQueue) IsFull() bool {
return (q.rear+1)%len(q.elements) == q.front
}
/**
* Your MyCircularQueue object will be instantiated and called as such:
* obj := Constructor(k);
* param_1 := obj.EnQueue(value);
* param_2 := obj.DeQueue();
* param_3 := obj.Front();
* param_4 := obj.Rear();
* param_5 := obj.IsEmpty();
* param_6 := obj.IsFull();
*/
2 )方案2:基于链表
type MyCircularQueue struct {
head, tail *ListNode
capacity, size int
}
func Constructor(k int) MyCircularQueue {
return MyCircularQueue{capacity: k}
}
func (q *MyCircularQueue) EnQueue(value int) bool {
if q.IsFull() {
return false
}
node := &ListNode{Val: value}
if q.head == nil {
q.head = node
q.tail = node
} else {
q.tail.Next = node
q.tail = node
}
q.size++
return true
}
func (q *MyCircularQueue) DeQueue() bool {
if q.IsEmpty() {
return false
}
q.head = q.head.Next
q.size--
return true
}
func (q MyCircularQueue) Front() int {
if q.IsEmpty() {
return -1
}
return q.head.Val
}
func (q MyCircularQueue) Rear() int {
if q.IsEmpty() {
return -1
}
return q.tail.Val
}
func (q MyCircularQueue) IsEmpty() bool {
return q.size == 0
}
func (q MyCircularQueue) IsFull() bool {
return q.size == q.capacity
}
/**
* Your MyCircularQueue object will be instantiated and called as such:
* obj := Constructor(k);
* param_1 := obj.EnQueue(value);
* param_2 := obj.DeQueue();
* param_3 := obj.Front();
* param_4 := obj.Rear();
* param_5 := obj.IsEmpty();
* param_6 := obj.IsFull();
*/
560



被折叠的 条评论
为什么被折叠?



