Python Queue class.. trouble understanding enqueue method - python

So I am trying to learn data structures in python and have moved on to trying to implement a queue. I understand how the data structure works. However I am now defining the enqueue method.
I am learning this on Codecademy btw.
The queue class looks like this:
from node import Node
class Queue:
def __init__(self, max_size=None):
self.head = None
self.tail = None
self.max_size = max_size
self.size = 0
# Add your enqueue method below:
def enqueue(self, value):
if self.has_space():
item_to_add = Node(value)
print("Adding " + str(item_to_add.get_value()) + " to the queue!")
if self.is_empty():
self.head = item_to_add
self.tail = item_to_add
else:
self.tail.set_next_node(item_to_add)
self.tail = item_to_add
self.size += 1
else:
print("Sorry, no more room!")
def peek(self):
if self.is_empty():
print("Nothing to see here!")
else:
return self.head.get_value()
def get_size(self):
return self.size
def has_space(self):
if self.max_size == None:
return True
else:
return self.max_size > self.get_size()
def is_empty(self):
return self.size == 0
The node class looks like this
class Node:
def __init__(self, value, next_node=None):
self.value = value
self.next_node = next_node
def set_next_node(self, next_node):
self.next_node = next_node
def get_next_node(self):
return self.next_node
def get_value(self):
return self.value
What I have trouble understanding is the enqueue method specifically this part:
self.tail.set_next_node(item_to_add)
self.tail = item_to_add
Why am I setting the tails next node the the node I am adding to the queue?
From what I gather I should set the item_to_add 's next node to be the current tail and then I should say self.tail_node is now the item_to_add?
Any help greatly appreciated as I am quite new to the data_structures and algorithms aspect of things.

When you enqueue, you are appending the node to the end. In the example you have stated, the queue's current last node is tail (accessed via self.tail)
When you enqueue to this queue, the current tail becomes the second to last node rather than the last. Hence, we do self.tail.set_next_node(item_to_add). This is because the current last node (i.e the tail)'s next reference is Null. You update it to the item_to_add, which will be the new last node and then change self.tail to item_to_add to indicate this is the new tail/last node.

Related

Reversed double linked list by python

why can't print reversed this double linked list by python?
always print 6 or None
please can anyone help me fast to pass this task
///////////////////////////////////////////////////////////////////////////
class Node:
def __init__(self, data=None, next=None, prev=None):
self.data = data
self.next = next
self.previous = prev
sample methods==>
def set_data(self, newData):
self.data = newData
def get_data(self):
return self.data
def set_next(self, newNext):
self.next = newNext
def get_next(self):
return self.next
def hasNext(self):
return self.next is not None
def set_previous(self, newprev):
self.previous = newprev
def get_previous(self):
return self.previous
def hasPrevious(self):
return self.previous is not None
class double===>
class DoubleLinkedList:
def __init__(self):
self.head = None
self.tail = None
def addAtStart(self, item):
newNode = Node(item)
if self.head is None:
self.head = self.tail = newNode
else:
newNode.set_next(self.head)
newNode.set_previous(None)
self.head.set_previous(newNode)
self.head = newNode
def size(self):
current = self.head
count = 0
while current is not None:
count += 1
current = current.get_next()
return count
here is the wrong method ==>
try to fix it without more changes
def printReverse(self):
current = self.head
while current:
temp = current.next
current.next = current.previous
current.previous = temp
current = current.previous
temp = self.head
self.head = self.tail
self.tail = temp
print("Nodes of doubly linked list reversed: ")
while current is not None:
print(current.data),
current = current.get_next()
call methods==>
new = DoubleLinkedList()
new.addAtStart(1)
new.addAtStart(2)
new.addAtStart(3)
new.printReverse()
Your printReverse seems to do something else than what its name suggests. I would think that this function would just iterate the list nodes in reversed order and print the values, but it actually reverses the list, and doesn't print the result because of a bug.
The error in your code is that the final loop has a condition that is guaranteed to be false. current is always None when it reaches that loop, so nothing gets printed there. This is easily fixed by initialising current just before the loop with:
current = self.head
That fixes your issue, but it is not nice to have a function that both reverses the list, and prints it. It is better practice to separate these two tasks. The method that reverses the list could be named reverse. Then add another method that allows iteration of the values in the list. This is done by defining __iter__. The caller can then easily print the list with that iterator.
Here is how that looks:
def reverse(self):
current = self.head
while current:
current.previous, current.next = current.next, current.previous
current = current.previous
self.head, self.tail = self.tail, self.head
def __iter__(self):
node = self.head
while node:
yield node.data
node = node.next
def __repr__(self):
return "->".join(map(repr, self))
The main program can then be:
lst = DoubleLinkedList()
lst.addAtStart(1)
lst.addAtStart(2)
lst.addAtStart(3)
print(lst)
lst.reverse()
print(lst)

Add Node function not working singly linked list python

I'm a Noob, struggling to understand and implement a singly linked list, that adds items at the tail. I believe the only code that is not working is the add function, which I can't figure out the logic for. I believe I want to set the first node to be the head, and then insert each other element at the tail, changing the pointer for head to point to the 2nd item when adding it, then the pointer for the 2nd item to point to the third etc., but can't figure out how to go about coding that (to deal with an unknown number of strings, here 3 for simplicity.
strings = ["one", "two", "three"]
class Node:
def __init__(self,data,nextNode=None):
# populate the Node, with data and pointer
self.data = data
self.nextNode = nextNode
def getData(self):
# method to get value of this node
return self.data
def setData(self,val):
# set value of node to val
self.data = val
def getNextNode(self):
# get the pointer to the next node
return self.nextNode
def setNextNode(self,val):
# set pointer to the next node
self.nextNode = val
class LinkedList:
def __init__(self, head = None, tail = None):
# initial properties of linked list, size 0
self.head = head
self.tail = tail
self.size = 0
def getSize(self):
# get size of linked list
return self.size
def addNode(self,data):
# Head should point to first node, which will have a value, and a Null pointer
if (self.size == 0):
newNode = Node(data, self.tail)
self.head.getNextNode() = newNode
else:
# All additional nodes should be inserted at tail, and with the pointers for the prior nodes changed to point to the new node
newNode = Node(data, self.tail)
self.tail = newNode
self.size += 1
return True
def printNode(self):
curr = self.head
while curr:
print(curr.data)#, curr.nextNode)
curr = curr.getNextNode()
mylist = LinkedList()
for i in strings:
mylist.addNode(i)
mylist.printNode()
# desired output: Head -> one --> two --> three/Tail
There were many little mistakes, please find them in code below. And let me know if you don't understand something.
One important change is a new node shouldn't have access to its next node. Its already the last node, so there can't be any node next to it. Also please pay close attention to else block of addNode function.
strings = ["one", "two", "three","four","five"]
class Node:
def __init__(self,data):
# populate the Node, with data and pointer
self.data = data
self.nextNode = None
def getData(self):
# method to get value of this node
return self.data
def setData(self,val):
# set value of node to val
self.data = val
def getNextNode(self):
# get the pointer to the next node
return self.nextNode
def setNextNode(self,val):
# set pointer to the next node
self.nextNode = val
class LinkedList:
def __init__(self, head = None, tail = None):
# initial properties of linked list, size 0
self.head = head
self.tail = tail
self.size = 0
def getSize(self):
# get size of linked list
return self.size
def addNode(self,data):
# Head should point to first node, which will have a value, and a Null pointer
if (self.size == 0):
self.head = Node(data)
self.tail = self.head
self.size = 1
else:
# All additional nodes should be inserted at tail, and with the pointers for the prior nodes changed to point to the new node
newNode = Node(data)
self.tail.nextNode = newNode
self.tail = newNode
self.size += 1
return True
def printNode(self):
curr = self.head
while curr:
print(curr.data)#, curr.nextNode)
curr = curr.getNextNode()
mylist = LinkedList()
for i in strings:
mylist.addNode(i)
mylist.printNode()

Understanding a Linked List implementation in Python

I have found an implementation of a Linked List in Python, online, but it doesn't have any explanation or comments.
I understand the underlying concepts of a Linked List, but there is one key part of the code I don't understand:
class Node:
def __init__(self, data):
self.data = data
self.next = None
def get_data(self):
return self.data
def get_next(self):
return self.next
def set_data(self, data):
self.data = data
def set_next(self, next):
self.next = next
class LinkedList:
def __init__(self):
self.head = None
def is_empty(self):
return self.head == None
def add(self, item):
temp = Node(item)
temp.set_next(self.head)
self.head = temp
def size(self):
current = self.head
count = 0
while current != None:
count += 1
current = current.get_next()
return count
def search(self, item):
current = self.head
while current != None:
if current.get_data() == item:
return True
else:
current = current.get_next()
return False
def remove(self, item):
current = self.head
previous = None
found = False
while not found:
if current.get_data() == item:
found = True
else:
previous = current
current = current.get_next()
if previous == None:
self.head = current.get_next()
else:
previous.set_next(current.get_next())
I don't understand how the size, search and remove methods in the LinkedList class are able to call functions from the Node class via the current variable, after setting it to self.head, which seems to be contained within the scope of the LinkedList class.
Is it because the add method sets self.head = temp, where temp is a Node object?
If possible, could someone explain how this works?
You stated that:
I don't understand how the size, search and remove methods in the LinkedList class are able to call functions from the Node class via the current variable, after setting it to self.head, which seems to be contained within the scope of the LinkedList class.
You can see that in the code, initializing a LinkedList performs this line of code:
self.head = None
Since the head is set to none, the size, search, and remove methods will not run through the whole code. Rather, it will stop when the self.head == None, which is pretty much in the beginning.
For example, let's take a look at the size method.
def size(self):
current = self.head
count = 0
while current != None:
count += 1
current = current.get_next()
return count
In this function, current is set to self.head which is null unless you have added any nodes by calling the add() method. More on that later.
count is set equal to 0. Then a while loop begins which only runs if the current is not None. But since the current is set to self.head which is None, the while loop will not run and the function will return count which is 0. This is a correct implementation because there are currently no nodes in the linkedlist.
Now onto how you can add nodes.
The add method:
def add(self, item):
temp = Node(item)
temp.set_next(self.head)
self.head = temp
Here, the add method takes in itself and an item. The item is an object of some sort whether it be a string, integer, float, etc. Now a variable temp is created and set to a new node which is finally using something from the Node class. Then, temp's next node is set to head and the head is set to temp. What this does is that the linked list continuously updates the head.
Like this:
(head)
NODE1
ADD ONE MORE NODE
(head)
NODE2 NODE1
And so on...
Happy Coding!

constructing a Queue linked list using only one head pointer

I'm trying to construct a Queue linked list using only a head pointer (no tail).
but i cant seem to enqueue at the end of the list.
example: at the moment the code will: c -> b -> a, however i would like reverse it a -> b -> c.
class Node:
'''A node for a linked list.'''
def __init__(self, initdata):
self.data = initdata
self.next = None
class Queue(object):
def __init__(self):
self.head = None
def enqueue(self, item):
"""Add an item onto the tail of the queue."""
if self.head == None:
temp = Node(item)
temp.next = self.head
self.head = temp
else:
current = self.head
while current != None:
current = current.next
if current == None:
temp = Node(item)
temp.next = current
current = temp
def dequeue(self):
if self.head == None:
raise IndexError("Can't dequeue from empty queue.")
else:
current_first = self.head
current = self.head.next
return current_first.data
This should do it:
class Node:
'''A node for a linked list.'''
def __init__(self, initdata):
self.data = initdata
self.next = None
class Queue(object):
def __init__(self):
self.head = None
def enqueue(self, item):
"""Add an item onto the tail of the queue."""
if self.head is None:
self.head = Node(item)
else:
current = self.head
while current.next is not None:
current = current.next
current.next = Node(item)
def dequeue(self):
if self.head is None:
raise IndexError("Can't dequeue from empty queue.")
else:
first = self.head
self.head = self.head.next
return first.data
Besides some logic fixes (we need to create a new node and store it in current.next, current is just a variable pointing to a node), note we use is operator for testing for None and Node constructor to set data (so we can create and assign new nodes without temp var).
For example:
q = Queue()
q.enqueue('a')
q.enqueue('b')
q.enqueue('c')
print(q.dequeue())
print(q.dequeue())
print(q.dequeue())
Outputs:
a
b
c
Btw, note that such structure requires O(N) insertion time and O(1) deletion (pop) time. Double-ended queue (like the standard collections.deque) will do both insertion and deletion in constant time.

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