Problem with dequeue method in array implementation of queue (Python) - python

This is my attempt to code an array implementation of a queue in python. All methods are working fine, but I don't understand why my Dequeue method isn't working. There is no error given by the program but the first item is not being dequeued.
class Queue:
def __init__(self, capacity):
self.capacity = capacity
self.rear = -1
self.front = -1
self.size = 0
self.current_list = [] # This going to be our queue.
def IsEmpty(self):
return self.size == 0
def IsFull(self):
return self.size == self.capacity
def Enqueue(self, x):
if self.IsFull():
return 'This queue is full. Cannot enqueue items.'
elif self.IsEmpty():
self.rear += 1
self.current_list.append(x)
else:
self.rear += 1
self.current_list[self.rear] = x
def Dequeue(self):
if self.IsEmpty():
return 'Cannot dequeue items as queue is empty.'
elif self.size == 1:
self.front +=1
del self.current_list[self.front]
self.front, self.rear = -1, -1
else:
self.front += 1
self.current_list.pop(self.front)
def GetFront(self):
return self.current_list[self.front]
def GetRear(self):
return self.current_list[self.rear]
my_queue = Queue(5)
my_queue.Enqueue(10)
print(my_queue.current_list)
my_queue.Enqueue(5)
print(my_queue.current_list)
my_queue.Dequeue()
print(my_queue.current_list)

You aren't keeping track of the size variable when adding or removing elements. Here's a version I fixed and tested further:
class Queue:
def __init__(self, capacity):
self.capacity = capacity
self.rear = -1
self.front = -1
self.size = 0
self.current_list = [] # This going to be our queue.
def IsEmpty(self):
return self.size == 0
def IsFull(self):
return self.size == self.capacity
def Enqueue(self, x):
if self.IsFull():
return 'This queue is full. Cannot enqueue items.'
self.rear += 1
self.current_list.append(x)
self.size += 1
def Dequeue(self):
if self.IsEmpty():
return 'Cannot dequeue items as queue is empty.'
elif self.size == 1:
self.current_list.pop()
self.front, self.rear = -1, -1
else:
self.front += 1
self.current_list.pop(self.front)
self.size -= 1
def GetFront(self):
return self.current_list[self.front]
def GetRear(self):
return self.current_list[self.rear]

Related

dequeue implementation in Queue class from book 'Data Structure and algorithms in python' by M. Goodrich

I am studying book 'Data Structure and algorithms in python' by M. Goodrich and was looking dequeue implementation in queue class, please see below:
class Queue:
DEFAULT_CAPACITY = 10
def __init__(self):
self._data = [None] * Queue.DEFAULT_CAPACITY
self._size = 0 # queue current size
self._front = 0
def __len__(self):
return self._size
def is_empty(self):
return self._size == 0
def enqueue(self, dt):
if self._size == len(self._data):
self._resize(2 * len(self._data))
empty = (self._front + self._size) % len(self._data)
self._data[empty] = dt
self._size += 1
def first(self):
if self.is_empty():
raise QueueisEmpty
return self._data[self._front]
def dequeue(self):
if self.is_empty():
raise QueueisEmpty("Queue is empty")
answer = self._data[self._front]
self._data[self._front] = None
self._front = (self._front + 1) % len(self._data)
self._size -= 1
return ret
def _resize(self, desired_size):
old = self._data
walk = self._front
self._data = [None] * desired_size
for i in range(self._size):
self._data[i] = old[walk]
walk = (1 + walk) % len(old)
self._front = 0
class QueueisEmpty(BaseException):
pass
if you look dequeue method you will see that it checks that queue is not empty then get a reference to the first element by
answer = self._data[self._front]
I am curious why the author is not used built-in self.first() method instead.
This way it will have two benefits in my opinion:
it will have a shorter code
it will take care of empty queue cases

Struggling to debug my leetcode solution for LRU Cache

I am working on the LeetCode problem LRU Cache and I want to understand why my code does not work.
My idea was to keep a queue of valid keys and a dictionary of tuples (isValid, value). Everytime get is called I wanted to make the next key on the queue invalid and update the dictionary tuple for that key to be (False, value).
I know that there are better solutions out there I just really want to know why mine doesn't work, so I can become a better debugger/programmer in general. Thank you so much in advance for any and all help!
This is my code so far:
class LRUCache:
def __init__(self, capacity: int):
self.d = dict()
self.capacity = capacity
self.validKeys = Queue()
def get(self, key: int) -> int:
(isValid, value) = self.d.get(key, (False, -1))
if isValid:
return value
else:
return -1
def put(self, key: int, value: int) -> None:
if self.validKeys.getSize() >= self.capacity:
lastUsedKey = self.validKeys.dequeue()
(_, val) = self.d[lastUsedKey]
self.d[lastUsedKey] = (False, val)
# only enqueue a new key if it doesn't exist in the cache already, was part of the problem statement
if self.d.get(key, None) is None:
self.d[key] = (True, value)
self.validKeys.enqueue(key)
This is the expected output:
[null,null,null,1,null,-1,null,-1,3,4]
This is my output:
[null,null,null,1,null,2,null,-1,3,4]
Note: I'm pretty sure my queue implementation is correct I've posted it below with the test cases I tested it with:
class Node:
def __init__(self, val):
self.prev = None
self.next = None
self.val = val
class Queue:
def __init__(self):
self.head = None
self.tail = self.head
self.size = 0
def enqueue(self, val):
if self.size == 0:
self.head = Node(val)
self.tail = self.head
else:
self.tail.next = Node(val)
self.tail = self.tail.next
self.size += 1
def dequeue(self):
if self.size == 0:
raise "Queue empty"
else:
val = self.head.val
self.head = self.head.next
self.size -= 1
return val
def getSize(self):
return self.size
def __repr__(self):
curr = self.head
res = ''
while curr is not None:
res += str(curr.val)
curr = curr.next
return res
obj = Queue()
assert obj.getSize() == 0
obj.enqueue(1)
assert obj.getSize() == 1
assert obj.dequeue() == 1
assert obj.getSize() == 0
obj.enqueue(1)
obj.enqueue(2)
obj.enqueue(3)
assert obj.getSize() == 3
assert obj.dequeue() == 1
assert obj.dequeue() == 2
assert obj.dequeue() == 3
assert obj.getSize() == 0

Python: CircularQueue doubles when size increases

I am trying to modify the class so the capacity automatically increases when I exceed the current capacity. When trying to add to a full queue, the capacity doubles.
I have created a new list with twice the original capacity.Enqueue the items from the original list onto the new list keeping track of the new front and back.
class CircularQueue:
def __init__(self,capacity):
self.items =[None]*capacity
self.MAX_QUEUE = capacity
self.front = 0
self.back = self.MAX_QUEUE - 1
self.count = 0
def is_full(self):
return self.count == self.MAX_QUEUE
def is_empty(self):
return self.count == 0
def size(self):
return self.count
def enqueue(self,item):
if not self.is_full():
self.back = (self.back+1)%self.MAX_QUEUE
self.items[self.back] = item
self.count +=1
else:
double_of_self_items = len(self.items)*2
new_list = [None]* double_of_self_items
MAX_QUEUE = double_of_self_items
back = MAX_QUEUE - 1
count = 0
back = (back + 1) % MAX_QUEUE
new_list[back] = self.items[back]
count += 1
print(new_list)
return new_list
def dequeue(self):
if not self.is_empty():
item = self.items[self.front]
self.front =(self.front+1)% self.MAX_QUEUE
self.count -=1
return item
else:
raise IndexError("The queue is empty.")
def peek(self):
if not self.is_empty():
item = self.items[self.front]
return item
else:
raise IndexError("The queue is empty.")
def __str__(self):
my_list = []
for i in self.items[self.front:]:
my_list.append(i)
for i in self.items[:self.back + 1]:
my_list.append(i)
return str(my_list)
q = CircularQueue(2)
q.enqueue(10)
q.dequeue()
q.enqueue(20)
q.enqueue(30)
q.enqueue(40)
print(q.size())
print(q.dequeue())
print(q.dequeue())
print(q.dequeue())
Excepted result:
3
20
30
40
Actual Result:
[30, None, None, None]
[20, None, None, None]
[30, None, None, None]
[20, None, None, None]
[30, None, None, None]
[20, None, None, None]
2
I'm not sure what you have the code you have, but in your enqueue method, simply check if you're full, increase the size if you are and then add the new item. That should simplify your logic and make your code more maintainable by having less flows.
def enqueue(self,item):
if is_full():
self.items = self.items + [None] * self.SOME_KIND_OF_INCREASE_DEFAULT
self.MAX_QUEUE = len(self.items)
self.back = (self.back+1)%self.MAX_QUEUE
self.items[self.back] = item
self.count +=1

Implemeting custom iterable object in python

This is my implementation of a custom singly linked list in Python.
class SList:
def __init__(self):
self.root = None
self.size = 0
def insert(self, item):
if not item:
raise ValueError('Cannot add None item to a list')
self.size += 1
if self.root is None:
self.root = Node(item)
else:
p = Node(item)
p.next = self.root
self.root = p
"""Remove the element at the specific index"""
def remove(self, index):
if index < 0 or index >= self.size:
raise ValueError('Index cannot be negative or greater than the size of the list')
current = self.root
if index == 0:
self.root = self.root.next
else:
for _ in range(index -1):
current = current.next
p = current.next.next
if p is not None:
current.next = p
else:
current.next = None
self.size -= 1
def __len__(self):
return self.size
def __repr__(self):
res = '[ '
current = self.root
while current is not None:
res += str(current.data)
res += ' '
current = current.next
res += ']'
return res
def __iter__(self):
return self
def next(self):
........
This is the Node object
class Node:
def __init__(self, data):
try:
if not data:
raise ValueError
self.data = data
self.next = None
except ValueError:
raise ValueError('Node cannot be instantiated without an item')
I'm at a little loss at implementing the iter method. I see there are multiple ways to implement it and yield seems to be the common way forward. Would appreciate some help in implmenting it with yield
You can make your class iterable by making its __iter__ method a generator.
Here's some code that runs correctly on Python 2 or Python 3.
from __future__ import print_function
class Node(object):
def __init__(self, data):
if data is None:
raise ValueError('Node cannot be instantiated without an item')
self.data = data
self.nextnode = None
def __repr__(self):
return 'Node({})'.format(self.data)
class SList(object):
def __init__(self):
self.root = None
self.size = 0
def insert(self, item):
if item is None:
raise ValueError('Cannot add None item to a list')
self.size += 1
if self.root is None:
self.root = Node(item)
else:
p = Node(item)
p.nextnode = self.root
self.root = p
def remove(self, index):
""" Remove the element at the specific index """
if index < 0 or index >= self.size:
raise ValueError('Index cannot be negative or greater than the size of the list')
current = self.root
if index == 0:
self.root = self.root.nextnode
else:
for _ in range(index - 1):
current = current.nextnode
current.nextnode = current.nextnode.nextnode
self.size -= 1
def __len__(self):
return self.size
def __repr__(self):
res = []
current = self.root
while current is not None:
res.append(current.data)
current = current.nextnode
return str(res)
def __iter__(self):
current = self.root
while current is not None:
yield current
current = current.nextnode
# test
a = SList()
for c in 'ABCDE':
a.insert(c)
print(a)
gen = iter(a)
print('root', next(gen))
for node in gen:
print(node)
a.remove(2)
print(list(a))
for node in a:
print(node)
output
['E', 'D', 'C', 'B', 'A']
root Node(E)
Node(D)
Node(C)
Node(B)
Node(A)
[Node(E), Node(D), Node(B), Node(A)]
Node(E)
Node(D)
Node(B)
Node(A)
Try to follow this explanation:
pythontips.com/2013/09/29/the-python-yield-keyword-explained
In short and simplified form - in order to create a generator, you should create a function that contains the yield keyword once or more. Anytime yield is reached in the function execution, it is put on hold, and passes the value after the keyword to the caller.
def my_gen(arg):
yield arg * 10
for i in xrange(5):
if i / 2 == 0:
yield i
for x in my_gen(3):
print(x)
Will print:
30
0
2
4
The constructor of the Node class is also faulty, in addition to catching your own exception, you also have an error with your if condition not data will be True not only if data is False or None, but also if data is 0,an empty list, empty string and many more. Use data is None instead.

Python Linked List Queue

I am trying to make a linked list queue in python and I cannot figure out how to return the size and the first item in the list...which seems pretty easy. I can insert and delete, but I cannot return the size or first item. Any thoughts??
class Node(object):
def __init__(self, item = None):
self.item = item
self.next = None
self.previous = None
class Queue(object):
def __init__(self):
"""post: creates an empty FIFO queue"""
self.length = 0
self.head = None
self.tail = None
def enqueue(self, x):
"""post: adds x at back of queue"""
newNode = Node(x)
newNode.next = None
if self.head == None:
self.head = newNode
self.tail = newNode
else:
self.tail.next = newNode
newNode.previous = self.tail
self.tail = newNode
def dequeue (self):
"""pre: self.size() > 0
post: removes and returns the front item"""
item = self.head.item
self.head = self.head.next
self.length = self.length - 1
if self.length == 0:
self.last = None
return item
def front(self):
"""pre: self.size() > 0
post: returns first item in queue"""
return item[0]
def size(self):
"""post: returns the number of itemes in queue"""
To efficiently be able to report the length of the linked list, you need to incriment it each time you add an element and decrement it each time you remove one. You're already doing the latter, but not the former.
So, just add self.length += 1 somewhere in your enqueue method, then size() can simple be return self.length
As for the first element in your queue, it will always be the item in the head node. So front() can be return self.head.item
Python lists already do what you're describing. Some examples:
# create a list
l = ['foo', 'bar']
# get the first item
print(l.pop(0))
# add an item
l.append(42)
print(l)
# get the size
print(len(l))
Your code in those two methods doesn't make any sense. How are you indexing into item? It's just a field of the Node class, not an array. Why didn't front() immediately lead you to thinking about head?
Surprisingly enough, the rest of your code seems okay. Here's what you need:
def front(self):
return self.head.item
def size(self):
return self.length
Also, you're not incrementing self.length in your enqueue() method.
The fact that you are having trouble with these should be a useful clue to you that you don't really understand the rest of the code. I've seen beginners often get mired in this trial-and-error approach, where you muck around with something until it works, usually starting with some code you got from somewhere. This leads to painfully brittle code, because your understanding is also brittle. This is not the way to write sensible code. At best it's a starting point for building your understanding - in which case, mucking around is exactly the right thing to do. Learn by experimentation and all that.
I recommend you read through the code you posted carefully and build a reasonably complete mental model of how it operates. Draw pictures or whatever helps you understand the pieces and the processes they implement. The depth of your mental model is a critical component of programming skill.
Also, you don't really need to go to all the trouble of writing these classes, other than as an exercise or something. Python lists already have methods that enable them to be used as queues.
First thing that jumps out at me is when you enqueue you need to increment the length of the list. size() should just need to return the length of the list once you've done that.
And then to access the first item of the list you appear to be trying to use list syntax which your list does not support (at least in the code I can see). Instead return self.head
class Node:
def init(self, data):
self.data = data
self.next = None
class Queue:
def __init__(self):
self.front = None
self.rear = None
self.size = 0
def enQueue(self, data):
temp = Node(data)
if self.front == None:
self.front = self.rear = temp
self.size += 1 # get track of size
return
self.rear.next = temp
self.rear = temp
self.size += 1
def deQueue(self):
if self.front == None:
return
temp = self.front
self.front = self.front.next
if self.front == None:
self.rear = None
del temp
self.size -= 1
def isEmpty(self):
return self.front == None
def getSize(self):
return self.size
def getFront(self):
if self.size > 0:
return self.front.data
else:
return
def getRear(self):
if self.size > 0:
return self.rear.data
else:
return
def printQueue(self):
queue = []
curr = self.front
while curr != None:
queue.append(curr.data)
curr = curr.next
print(queue)
_NodeLinked class is to create nodes:
class _NodeLinked:
# slots is memory efficient way to store the instance attributes
__slots__ = '_element', '_next'
def __init__(self, element, next):
self._element = element
self._next = next
class QueuesLinked:
# each instance being initialized an empty list
def __init__(self):
self._front = None
self._rear = None
self._size = 0
def __len__(self):
return self._size
def isempty(self):
return self._size == 0
# adding a node to the end of the list
def enqueue(self, e):
newest = _NodeLinked(e, None)
if self.isempty():
self._front = newest
else:
self._rear._next = newest
self._rear = newest
self._size += 1
# removing first node
def dequeue(self):
if self.isempty():
print('Queue is empty')
return
e = self._front._element
self._front = self._front._next
self._size -= 1
if self.isempty():
self._rear = None
return e
def first(self):
if self.isempty():
print('Queue is empty')
return
return self._front._element
def display(self):
p = self._front
while p:
print(p._element,end=' <-- ')
p = p._next
print()

Categories