Python Linked List Queue - python

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()

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)

Python Queue class.. trouble understanding enqueue method

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.

Merging two sorted Doubly Linked Lists in python using recursion

I am trying to write a method that merges two sorted Doubly Linked Lists of integers, using recursion (it has to be recursive). The method creates and returns a new Doubly Linked List with the integer values in order. For example, if doublylinkedlist1 = [0-2-4] and doublylinkedlist2 = [1-3-5], the merge_sorted method would return [0-1-2-3-4-5].
However, when I run my code below:
class EmptyCollection(Exception):
pass
class DoublyLinkedList:
class Node:
def __init__(self, data=None, next=None, prev=None):
self.data = data
self.next = next
self.prev = prev
def disconnect(self):
self.data = None
self.next = None
self.prev = None
def __init__(self):
self.header = DoublyLinkedList.Node()
self.trailer = DoublyLinkedList.Node()
self.header.next = self.trailer
self.trailer.prev = self.header
self.size = 0
def __len__(self):
return self.size
def is_empty(self):
return (len(self) == 0)
def first_node(self):
if (self.is_empty()):
raise EmptyCollection("List is empty")
return self.header.next
def last_node(self):
if (self.is_empty()):
raise EmptyCollection("List is empty")
return self.trailer.prev
def add_first(self, elem):
return self.add_after(self.header, elem)
def add_last(self, elem):
return self.add_after(self.trailer.prev, elem)
def add_after(self, node, elem):
prev = node
succ = node.next
new_node = DoublyLinkedList.Node()
new_node.data = elem
new_node.prev = prev
new_node.next = succ
prev.next = new_node
succ.prev = new_node
self.size += 1
return new_node
def add_before(self, node, elem):
return self.add_after(node.prev, elem)
def delete(self, node):
prev = node.prev
succ = node.next
prev.next = succ
succ.prev = prev
self.size -= 1
data = node.data
node.disconnect()
return data
def __iter__(self):
if(self.is_empty()):
return
cursor = self.first_node()
while(cursor is not self.trailer):
yield cursor.data
cursor = cursor.next
def __str__(self):
return '[' + '<-->'.join([str(elem) for elem in self]) + ']'
def __repr__(self):
return str(self)
def merge_linked_lists(srt_lnk_lst1, srt_lnk_lst2):
return merge_sublists(srt_lnk_lst1.first_node(), srt_lnk_lst2.first_node())
def merge_sublists(a, b):
result = DoublyLinkedList()
if a is not None and b is not None:
if a.data < b.data:
result.add_last(a.data)
return merge_sublists(a.next, b)
else:
result.add_last(b.data)
return merge_sublists(a, b.next)
elif a is not None:
result.add_last(a.data)
return merge_sublists(a.next, b)
elif b is not None:
result.add_last(b.data)
return merge_sublists(a, b.next)
return result
ll1 = DoublyLinkedList()
for i in range(0,10,2):
ll1.add_last(i)
ll2 = DoublyLinkedList()
for i in range(1,10,2):
ll2.add_last(i)
merged = merge_linked_lists(ll1, ll2)
print(merged)
I get an error in my merge_sublists function that says I cannot add 'int' and 'Nonetype'.
Is there any way I can modify my merge_sublists method to make the function work properly? Any help is appreciated.
When you hit the end of the a list, although the object isn't None, you have a.data as None. You need to check the data as well as the list objects.
The problem is caused by the dummy list nodes that are placed at the start and end of the list. Although the code checks for empty lists, and skips over the initial dummy node, there is no check for the final dummy node at the end of the list. So while following a.next and b.next, it eventually encounters a dummy node, which has None as the value of data. The error occurs when it tries to compare None to the data value in another node.
You could check if a.next and b.next are None at the top of merge_sublists, but you will still need to make sure you only end up with a single dummy node at the end of the merged list.
It might be simplest to eliminate the dummy nodes altogether, and just check for an empty list when adding new nodes.

Implementing Doubly Linked List in Python

I was trying to implement a doubly linked list with the following functions:
_insertItemAfterNode(self,index)
_nodeBeforeIndex(self, index)
insertItemAtTheFront(self,item)
insertItemAtTheEnd(self,item)
insertItemAtIndex(self, index, item)
The last three functions should use the first two private methods.
This is what I have so far but I can't seem to work it. Any help is appreciated!!!
# DoublyLinkedLists
class Node(object):
def __init__(self, prev = None, data=None, next = None):
self._prev = prev
self._data = data
self._next = next
def __str__(self):
return str(self._data)
def __repr__(self):
return "Node(%s,%s,%s)" % (repr(self._prev), repr(self._data), repr (self._next))
def __eq__(self, other):
if other == None:
return False
else:
return self._prev == other._prev and self._data == other._data and self._next == other._next`enter code here`
class DoublyLinkedList(object):
def __init__(self):
self._first = Node(None, None, None)
self._length = 0
self._last = Node(None, None, None)
def __len__(self):
return self._length
def _insertItemAfterNode(self,item,aNode):
newNode = Node(aNode._prev, item, aNode._next)
aNode._next= newNode._prev
aNode._prev=newNode._next
self._length += 1
def _nodeBeforeIndex(self, index):
if 0 <= index <= self._length:
aNode = self._first
for i in range(index):
aNode = aNode._next
return aNode
else:
raise IndexError
def _nodeAfterIndex(self, index):
if 0<= index <= self.length:
aNode = self._last
for i in range(index):
aNode = aNode._prev
return aNode
else:
raise IndexError
def __getitem__(self, index):
return self._nodeBeforeIndex(index)._next._data
def insertAtEnd(self, item):
self._nodeAfterIndex(item)
def __iter__(self):
return DoublyLinkedListIterator(self)
def __setitem__(self, index, item):
self._nodeBeforeIndex(index)._next._data = item
def insertItemAtTheFront(self, item):
self._insertItemAfterNode(item, self._nodeBeforeIndex(0))
def insertItemAtTheEnd(self, item):
self._insertItemAfterNode(item, self._nodeBeforeIndex(self._length))
def insertItemAtIndex(self, index, item):
'''Valid range 0 <= index <= length.'''
self._insertItemAfterNode(item, self._nodeBeforeIndex(index))
def __iter__(self):
return DoublyLinkedListIterator(self)
def __repr__(self):
#used by print in abscence of __str__ .
plist = []
for item in self:
plist.append(item)
return "DoublyLinkedList(%s)" % str(plist)
class DoublyLinkedListIterator(object):
def __init__(self, aList):
self._list = aList
self._currentIndex = -1
self._currentNode = self._list._first
def __iter__(self):
return self
def __next__(self):
if self._currentIndex == self._list._length - 1:
raise StopIteration
else:
self._currentIndex += 1
self._currentNode = self._currentNode._next
return self._currentNode._data
def main():
x = DoublyLinkedList()
x.insertItemAtTheEnd(45)
print(x)
main()
I see two immediate issues with your code. There may be more issues that I haven't noticed, but these will probably prevent you from seeing any others until they are fixed.
The first issue is very simple. You have two sentinel nodes, _first and _last in your DoublyLinkedList class. However, they're not linked to each other, so when more nodes are added later, they won't be connected to both sentinels like they should be.
You can fix this by changing the __init__ method:
def __init__(self):
self._first = Node(None, None, None)
self._length = 0
self._last = Node(self._first, None, None) # pass first node as an arg here
self._first._next = self._last # make a link back too
The second issue is how you're adding nodes. There are a couple of places where you're assigning values from the _prev or _next attributes of a node, rather than referring to the node itself.
Lets think of a list containing A and C nodes, and you want to insert B in between them. You need to make B's node link to both A and C, and then modify C and A to link back to it. In your code, A is aNode, B is newNode and C is (at the start) aNode._next.
def _insertItemAfterNode(self, item, aNode):
newNode = Node(aNode, item, aNode._next) # link B to A and C
aNode._next._prev = newNode # link C back to B
aNode._next = newNode # and A to B too!
self._length += 1
There are a few things strange with your code. Let's dig into the first problem that I found:
def _insertItemAfterNode(self,item,aNode):
newNode = Node(aNode._prev, item, aNode._next)
aNode._next= newNode._prev
aNode._prev=newNode._next
self._length += 1
Assume that you have:
prevNode <-> aNode <-> nextNode
You now create a newNode which points to prevNode as its previous and nextNode as its follow-up. Then you reverse the pointers of aNode. prevNode still thinks its following node is aNode, but aNode now thinks that its following node is prevNode again.
/---------\
/----> aNode < v
prevNode <--------/ \-- nextNode
^ ^
\---- newNode --/
Which is not nearly what you want:
prevNode <-> aNode <-> newNode <-> nextNode
Here's a better version:
def _insertItemAfterNode(self,item,aNode):
# If the new Node follows aNode, than its preceeding node is aNode,
# not aNode._prev!
newNode = Node(aNode, item, aNode._next)
# Now we need to make aNode point at its new following Node, newNode
aNode._next = newNode
# And finally, we need to make the following Node notice that
# its preceeding Node has changed.
newNode._next._prev = newNode
self._length += 1
This doesn't care about any edge cases, for example what to do if aNode is the last node in the linked list.
What I recommend is that you take out a piece of paper and draw how the different links need to be changed for each of the operations that you need to make, because it is hard to keep all this in your head.
Make sure that you look at all the edge cases, ie. putting into an empty list, putting in item into the first and last positions.
And finally, while shuffling links around, always double check where each link is pointing at each instruction, and not to drop any nodes accidentally.

Linked queue in python can't tell if it's empty

So I built a linked queue class in python that looks like this.
class queue:
class _Node:
def __init__(self, elem, next):
self._elem = elem
self._next = next
def __init__(self):
self._rear = None
self._front = None
self._size = 0
def enqueue(self, value):
if self.isEmpty:
self._front = self._Node(value, None)
self._rear = self._front
self._size += 1
return
self._rear._next = self._Node(value, None)
self._rear = self._rear._next
self._size += 1
return
def dequeue(self):
retVal = self._front._elem
self._front = self._front._next
self._size -= 1
if self.isEmpty:
self._rear = None
return retVal
def __len__(self):
return self._size
def isEmpty():
return len(self) == 0
I'm using this class in order to create a really basic print queue that feeds into two printers. My problem is, my isEmpty function in the class seems to think that it is always empty. If I add 3 print jobs, then try to display them, it will only display the last one because the enqueue function thinks that the queue is empty. I just can't seem to figure out why so any help would be much appreciated.
The problem you are actually encountering is that you are not calling the method, but just referring to the boolean value of the method object itself, which is always true. It should be:
if self.isEmpty():

Categories