Doubly Linked list with iterator [closed] - python

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 11 months ago.
Improve this question
I'm trying to implement the doubly-linked list in these singly-linked list operations, but how do I properly implement the previous Node (antNode) in the functions addNode and elimNode?
Almost everything that is done in insNode is applicable in addNode function.
class ListNode:
def __init__(self, data, nextNode=None):
self.data = data
self.nextNode = nextNode
self.antNode = None
class DoublyLinkedListIterator:
def __init__(self, firstNode=None):
self.firstNode = firstNode
self.lastNode = firstNode
self.iterator = firstNode
if firstNode:
self.size = 1
else:
self.size = 0
def addNode(self, data): # Add a Node after the iterator.
"""Pre condition: Iterator defined
Pos condition: The data is inserted into a node after the
iterator. The iterator stands over this node.
"""
newNode = ListNode(data,None) # treats the empty list
newNode.nextNode = None
newNode.antNode = None
if(self.size == 0): # treats the empty list
self.iterator = newNode
self.firstNode = newNode
self.lastNode = newNode
elif self.iterator == self.lastNode:
self.lastNode.nextNode = newNode
self.iterator = newNode
self.lastNode = newNode
else:
newNode.nextNode = self.iterator.nextNode
self.iterator.nextNode = newNode
self.iterator = newNode
self.size += 1
return True
def elimNode(self): # Eliminates the element over the iterator and
# advances the iterator to the next node.
if(self.iterator == self.firstNode):
if(self.lastNode == self.firstNode):
self.lastNode = None
self.firstNode = None
self.iterator = None
else: # more than one node
#self.firstNode = self.firstNode.nextNode
self.firstNode = self.firstNode.nextNode
self.iterator.nextNode = None
self.iterator = self.firstNode
else: # iterator can be under the last or an inner element
currentNode = self.firstNode
while currentNode.nextNode != self.iterator:
currentNode = currentNode.nextNode
if self.iterator == self.lastNode:
self.lastNode = currentNode
self.iterator.nextNode = None
self.iterator = None
currentNode.nextNode = None
else:
currentNode.nextNode = self.iterator.nextNode
currentNode = self.iterator
self.iterator = self.iterator.nextNode
currentNode.nextNode = None
self.size = self.size - 1
return True
The function insNode that inserts a node before the iterator is like this with doubly linked list:
def insNode(self, data): # insert a node before the iterator
"""Pre condition: Iterator defined
Pos condition: The data is inserted into a node before the iterator.
The iterator stands over this node.
"""
newNode = ListNode(data, None) # treats the empty list
newNode.nextNode = None
newNode.antNode = None
if (self.size == 0): # treats the empty list
self.iterator = newNode
self.firstNode = newNode
self.lastNode = newNode
elif self.iterator == self.firstNode: # iterator is on the first element
newNode.nextNode = self.firstNode
self.iterator.antNode = newNode
self.firstNode = newNode
self.iterator = newNode
else: # iterator is on an inner element
newNode.antNode = self.iterator.antNode
self.iterator.antNode.nextNode = newNode
self.iterator.antNode = newNode
self.iterator = newNode
self.size += 1
return True

The answer is: yes you should do similar changes in insNode. However, much of the code is alike, so I would create a helper function to perform the actions these two methods have in common. Also, let the ListNode constructor take an optional argument also for the antNode attribute.
Not your question, but:
The elimNode method should better check that self.iterator is not None.
I find the name iterator confusing, since iterator is a very specific concept in Python, and it is not this. So I would rename that to cursor or currentNode or something. I can understand that this was given in some template code, or exercise, but then it doesn't really speak in favour of the quality of that teaching material.
I don't really see the purpose for the optional node parameter in the constructor of the main class. I would either omit it, or else let it accept a variable number of data values. That would be more practical.
Here is how it could look:
class ListNode:
def __init__(self, data, antNode=None, nextNode=None):
self.data = data
self.nextNode = nextNode
self.antNode = antNode
class DoublyLinkedListWithCursor:
def __init__(self):
self.firstNode = self.lastNode = self.currentNode = None
self.size = 0
def _insertBetween(self, data, before, after):
# Helper function for common logic in insNode and addNode methods
self.currentNode = ListNode(data, before, after)
if after:
after.antNode = self.currentNode
else:
self.lastNode = self.currentNode
if before:
before.nextNode = self.currentNode
else:
self.firstNode = self.currentNode
self.size += 1
def insNode(self, data):
self._insertBetween(data, self.currentNode.antNode if self.currentNode else self.lastNode, self.currentNode)
def addNode(self, data):
self._insertBetween(data, self.currentNode, self.currentNode.nextNode if self.currentNode else self.firstNode)
def elimNode(self):
if not self.currentNode: # Sanity check
return False
if self.currentNode.antNode:
self.currentNode.antNode.nextNode = self.currentNode.nextNode
else:
self.firstNode = self.currentNode.nextNode
if self.currentNode.nextNode:
self.currentNode.nextNode.antNode = self.currentNode.antNode
else:
self.lastNode = self.currentNode.antNode
self.currentNode = self.currentNode.nextNode
self.size -= 1
return True

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)

calling a method in another method errors

class Node:
def __init__(self, data):
self.data = data
self.ref = None
class LinkedList:
def __init__(self):
self.head = None
def show(self):
if self.head is None:
print("This linked lists is empty")
else:
currentnode = self.head
while currentnode is not None:
print(currentnode.data, end=" --> ")
currentnode = currentnode.ref
def addelement(self, value):
newnode = Node(value)
newnode.ref = self.head
self.head = newnode
def lenofll(self , i = 0):
while self.head is not None:
i = i +1
self.head = self.head.ref
return i
def middle(self):
i = 0
lent = self.lenofll()
if self.head is None: # self.head changed to None after calling lenofll method.
print("linked list is empty")
I wanted to get the length of linked lists in the middle method. But as I called self.lenofll(), it changed the self.head to None.
What can I do to fix this?
Indeed, doing self.head = self.head.ref modifies the head. You should not make any modifications to self.head in a method whose job is just to search in the list -- without modifying anything to it.
As you can see, that method keeps looping until self.head is not None is not true, i.e. when self.head is None. No wonder that self.head is None after running this method!
Use a local variable for this iteration instead:
def lenofll(self, i = 0):
node = self.head # use local variable
while node is not None:
i += 1
node = node.ref
return i

Linked list implementation in python 3

I am still a beginner in programming. I learned the basics in Python. Right now I'm learning data structures and algorithms.
I have implemented a linked list. But there is a problem inside it. My size is 0 after removing one element. I do not know where the error comes from.
This code was tested in Python 3.7.4.
class Node(object):
def __init__(self, data):
self.data = data
self.nextNode = None
class LinkedList(object):
def __init__(self):
self.head = None
self.size = 0
# O(1)
def insertStart(self, data): # insert data at beginnning of the list
self.size += 1
newNode = Node(data)
if not self.head: # the head is None
self.head = newNode
else: # the head is not None
newNode.nextNode = self.head
self.head = newNode
def remove(self,data):
if self.head is None:
return
self.size-=self.size
currentNode=self.head
previousNode=None
while currentNode.data != data:
previousNode=currentNode
currentNode=currentNode.nextNode
if previousNode is None:
self.head = currentNode.nextNode
else:
previousNode.nextNode=currentNode.nextNode
# O(1)
def size1(self):
return self.size
# O(N)
def size2(self):
actualNode = self.head
size = 0
while actualNode is not None:
size += 1
actualNode = actualNode.nextNode
return size
# O(N)
def insertEnd(self, data):
self.size += 1
newNode = Node(data)
actualNode = self.head
while actualNode.nextNode is not None:
actualNode = actualNode.nextNode
actualNode.nextNode = newNode
def traverseList(self):
actualNode = self.head
while actualNode is not None:
print("%d " % actualNode.data)
actualNode = actualNode.nextNode
a=LinkedList()
a.insertStart(3)
a.insertStart(4)
a.insertEnd(5)
#a.remove(3)
#a.remove(4)
a.remove(5)
print(a.traverseList())
print(a.size1())
You're subtracting self.size from self.size, which will obviously return 0. You just want to remove 1 (self.size -= 1)
Also, you have another bug. What happens if you try to remove a node which doesn't exist? Your condition while currentNode.data != data: will raise a NoneType error, because it will eventually reach the end of the list (None) without having found the 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.

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