Я изучаю Очередь из задачи Дизайн круговой очереди - LeetCode
Design your implementation of the circular queue. The circular queue is a linear data structure in which the operations are performed based on FIFO (First In First Out) principle and the last position is connected back to the first position to make a circle. It is also called "Ring Buffer".
One of the benefits of the circular queue is that we can make use of the spaces in front of the queue. In a normal queue, once the queue becomes full, we cannot insert the next element even if there is a space in front of the queue. But using the circular queue, we can use the space to store new values.
Your implementation should support following operations:
MyCircularQueue(k): Constructor, set the size of the queue to be k.Front: Get the front item from the queue. If the queue is empty, return -1.Rear: Get the last item from the queue. If the queue is empty, return -1.enQueue(value): Insert an element into the circular queue. Return true if the operation is successful.deQueue(): Delete an element from the circular queue. Return true if the operation is successful.isEmpty(): Checks whether the circular queue is empty or not.isFull(): Checks whether the circular queue is full or not.Example:
MyCircularQueue circularQueue = new MyCircularQueue(3); // set the size to be 3 circularQueue.enQueue(1); // return true circularQueue.enQueue(2); // return true circularQueue.enQueue(3); // return true circularQueue.enQueue(4); // return false, the queue is full circularQueue.Rear(); // return 3 circularQueue.isFull(); // return true circularQueue.deQueue(); // return true circularQueue.enQueue(4); // return true circularQueue.Rear(); // return 4Note:
- All values will be in the range of [0, 1000].
- The number of operations will be in the range of [1, 1000].
- Please do not use the built-in Queue library.
Я подражаю учебнику Гудрича Структуры данных и алгоритмы в Python и написал понятное решение.
1, только три данных (_queue, _len и _front)
2, инициализировать self._front как 0
class MyCircularQueue:
#Runtime: 76 ms, faster than 53.17%
#Memory Usage: 13.6 MB, less than 7.24%
def __init__(self, k: int):
"""
Initialize your data structure here. Set the size of the queue to be k.
"""
self._queue = [None] * k #the basic
self._capacity = k
self._len = 0
#The first three categorize as a group, the 4th as the second group
self._front = 0
#self._rear is not necessary, because rear = front + length -1
def enQueue(self, value: int) -> bool:
"""
Insert an element into the circular queue. Return true if the operation is successful.
"""
if self.isFull(): return False
avail = (self._front + self._len) % (self._capacity)
self._queue[avail] = value
self._len += 1
return True
def deQueue(self) -> bool:
"""
Delete an element from the circular queue. Return true if the operation is successful.
"""
if self.isEmpty():
return False
self._queue[self._front] = None #overrode the current node
self._front = (self._front+1) % self._capacity
self._len -= 1
return True
def Front(self) -> int:
"""
Get the front item from the queue.
"""
if not self.isEmpty():
return self._queue[self._front]
else:
return -1
def Rear(self) -> int:
"""
Get the last item from the queue.
"""
if not self.isEmpty():
_rear = (self._front + self._len - 1) % self._capacity
return self._queue[_rear]
else:
return -1
def isEmpty(self) -> bool:
"""
Checks whether the circular queue is empty or not.
"""
return self._len == 0
def isFull(self) -> bool:
"""
Checks whether the circular queue is full or not.
"""
return self._len == self._capacity
Дизайн Гудрича очень удобен для чтения с меньшими усилиями.
Тем не менее, при чтении других представленных материалов общепринятой практикой является инициализация self._fornt и self._rear как -1, хотя чтение или запись требуют усилий.
Выдержка из случая, производительность которого выше 98%
def deQueue(self):
"""
Delete an element from the circular queue. Return true if the operation is successful.
:rtype: bool
"""
if self.isEmpty():
return False
self.head = (self.head+1) % self.maxlen
self.currlen -= 1
if self.isEmpty(): #have to take care of self.head and self.tail
self.head = -1
self.tail = -1
#another submission which initialize front and rear =-1
def enQueue(self, value: 'int') -> 'bool':
"""
Insert an element into the circular queue. Return true if the operation is successful.
"""
if (self.len == self.capacity): return False
# To check if full
#if (self.rear == self.front - 1 or (self.rear == self.capacity - 1 and self.front == 0) )
if (self.front == -1):
self.front, self.rear = 0, 0
elif (self.rear == self.capacity - 1 and self.front != 0):
# make rear start (case when element was removed from start)
self.rear = 0
else:
self.rear = (self.rear + 1) % self.capacity
self.data[self.rear] = value
self.len += 1
return True
Поскольку python скрывает большинство деталей реализации,
Какое преимущество взять front или rear вместо -1?






Я резюмировал основные различия между общим решением и вашим решением:
rear, чтобы отметить хвостfront и rear на -1ifelse логические веткиВ общем, думаю, эти два решения мало чем отличаются, просто имеют разную направленность. Если вы хотите узнать небольшую разницу за этим, я объясню это для вас.
По вашему мнению, вы склонны использовать меньше переменных и пытаться унифицировать всю логику вместе, а также сделать код чистым и понятным.
Напротив, он хочет улучшить производительность (может быть, совсем немного) и сделать более качественную абстракцию. Я объясню это подробно:
Повышение производительности:
rear как «обмен места на время». В каждом месте, относящемся к rear, вы будете пересчитывать текущий rear по (self._front + self._len - 1) % self._capacity, а он просто берется из rear. Он кеширует rear для высокочастотного использования.Rear используется больше, чем enQueue и deQueue, вы можете использовать rear, чтобы уменьшить стоимость повторного расчета.ifelse логических ветвей в enQueue и deQueue. Это может немного повысить производительность в зависимости от конкретных условий. В частности, это уменьшает +-% работу при пустом, полном или одноэлементном корпусе.Абстракция:
Его решение — более объектно-ориентированный дизайн. какие свойства важны для циклической очереди? Конечно, front, rear и state(пустой, полный или еще что). Поэтому он сохраняет rear и назначает -1, когда он пуст, чтобы представлять особое состояние.
Хорошая абстракция пойдет на пользу функциональной масштабируемости. Например, мы хотим добавить больше функций к MyCircularQueue, возможно, rear и state помогут здесь.
Все это мое личное мнение, может и не верное, просто для информации. :)