doubly Linked list iterator python - python

I am constructing a doubly linked list and I am struggling on construct a doubly linked list iterator method in PYTHON.
This is my code so far
class DoubleListNode:
def __init__(self,data):
self.data=data
self.prev = None
self.next= None
class ListIterator:
def __init__(self):
self._current = self.head
def __iter__(self):
return self
def next(self):
if self.size == 0 :
raise StopIteration
else:
item = self._current.data
self._current=self._current.next
return item
class DoublyLinkedList:
def __init__(self):
self.head= None
self.tail= None
self.size = 0
def add(self,data):
newnode= DoubleListNode(data)
self.size+=1
if self.head is None:
self.head = newnode
self.tail = self.head
elif data < self.head.data: # before head
newnode.next = self.head
self.head.prev= newnode
self.head= newnode
elif data > self.tail.data: # at the end
newnode.prev= self.tail
self.tail.next= newnode
self.tail=newnode
else:
curNode = self.head
while curNode is not None and curNode.data < data:
curNode=curNode.next
newnode.next= curNode
newnode.prev=curNode.prev
curNode.prev.next= newnode
curNode.prev=newnode
def remove(self,data):
curNode=self.head
while curNode is not None and curNode.data!= data:
curNode= curNode.next
if curNode is not None:
self.size -= 1
if curNode is self.head:
self.head= curNode.next
else:
curNode.prev.next=curNode.next
if curNode is self.tail:
self.tail=curNode.prev
else:
curNode.next.prev=curNode.prev
When I run a test it said TypeError: iteration over non-sequence. Did I do something wrong ?

As posted, the code doesn't initialize (i.e. self.head isn't defined).
But overall, you are on the right track. Take a look at the source for Python's collections.OrderedDict for a worked-out example of traversing a doubly linked list.
Here's a simplified example:
class Link:
def __init__(self, value, prev=None, next=None):
self.value = value
self.prev = prev
self.next = next
def __iter__(self):
here = self
while here:
yield here.value
here = here.next
def __reversed__(self):
here = self
while here:
yield here.value
here = here.prev
if __name__ == '__main__':
a = Link('raymond')
b = Link('rachel', prev=a); a.next=b
c = Link('matthew', prev=b); b.next=c
print 'Forwards:'
for name in a:
print name
print
print 'Backwards:'
for name in reversed(c):
print name

I think there are two important things to fix.
First, your DoublyLinkedList class doesn't have an __iter__ method. You probably want to create one that returns a ListIterator instance. Perhaps you're trying to do this manually, but this would be the normal approach.
Second, you need to fix the code in your ListIterator to work properly. Currently your __init__ method doesn't initialize things correctly, and your next method tries to access member variables like size that don't exist.
Here's an implementation that I think will work:
def ListIterator(object):
def __init__(self, node):
self.current = node
def __iter__(self):
return self
def next(self):
if self.current is None:
raise StopIteration()
result = self.current.data
self.current = self.current.next
return result
class DoublyLinkedList(object):
# all your current stuff, plus:
def __iter__(self):
return ListIterator(self.head)
As a side note, in your current code you're defining classes with no bases. This is fine in Python 3 (where object will be the base by default), but in Python 2 this will result in getting an "old-style" class. Old-style classes are deprecated, and you'll find that some language features won't work properly with them (though not any of the features involved in iteration, as far as I know). On the other hand, if you are already using Python 3 then you need to define a __next__ method in the iterator class, rather than next (without the underscores).

Here is an example for Doubly Linked List class.
class Node:
def __init__(self, val):
self.data = val
self.next = None
self.prev = None
class LinkedList:
def __init__(self):
self.head = None
self.tail = None
self.count = 0
def insert(self, val):
newNode = Node(val)
if self.count == 0:
self.head = newNode
self.tail = newNode
else:
self.head.prev = newNode
newNode.next = self.head
self.head = newNode
self.count += 1
def insertToEnd(self, val):
newNode = Node(val)
if self.count == 0:
self.head = newNode
self.tail = newNode
else:
self.tail.next = newNode
newNode.prev = self.tail
self.tail = newNode
self.count += 1
def search(self, val):
p = self.head
while p is not None:
if p.data == val:
return p
p = p.next
def delete(self, val):
curNode = self.head
while curNode != None:
if curNode.data == val:
if curNode.prev != None:
curNode.prev.next = curNode.next
else:
self.head = curNode.next
if curNode.next != None:
curNode.next.prev = curNode.prev
else:
self.tail = curNode.prev
self.count -= 1
curNode = curNode.next
def show(self):
s = ""
p = self.head
while p is not None:
s += str(p.data) + ' ';
p = p.next
print(s + "| count: " + str(self.count))

Based on what you post, may I suggest:
class ListIterator:
# other stuff ...
def __iter__(self):
while self._current:
yield self._current.data
self._current = self._current.next
self._current = self.head # Reset the current pointer
You don't have to implement next()
Update
Here is an example usage:
for data in myListIterator:
print data
# Without reset, the second time around won't work:
for data in myListIterator:
print data

Related

error in creating a linked list using python

I am new to data structures.Tried to create a linkled list with a print function,but when running the program it is throwing an error stating "add_link takes one positional argument but 2 were given".Below is the code.Please help me out. thanks in advance
class node:
def __init__( self ,value, Next = None):
self.value = value
self.Next = None
newnode = None
def add_link(self,data):
if(self.Next == None):
self.Next = node(data)
newnode = self.Next
else:
newnode.Next = node(data)
newnode = newnode.Next
def print(self):
if(self.Next !=None):
print(self.node)
self.next.print()
# main
link = node(10)
link.add_link(20)
link.add_link(30)
link.add_link(40)
link.print()
You need to add self as an argument to the add_link() function:
def add_link(self, data):
if(self.Next == None):
self.Next = node(data)
newnode = self.Next
else:
newnode.Next = node(data)
newnode = newnode.Next
It will be better to create Node as a seprate class/structure, and LinkedList as different.
So that we can implement methods according to class.
class Node:
"""
#Summary: Node has a set of information and address to the next node.
"""
def __init__(self, data) -> None:
self.data = data
self.next = None
class SinglyLinkedList:
def __init__(self, item:Node) -> None:
# Head or start node for Singly Linked List
self.head = item
def add(self, new_item:Node) -> None:
"""
#Summary: Adde new item to Singly Linked List
#Param new_item(Node): New node item
#Return (None)
"""
# Check if Linked list is emplty or not.
if self.head == None:
self.head = new_item
else:
# Add a new item to an end.
last_node = self.head
while last_node.next != None:
last_node = last_node.next
last_node.next = new_item
def print(self):
"""Print Linked List"""
if self.head == None:
print("No item in Linked list")
else:
print("Linked List :")
tmp_node = self.head
while True:
print(tmp_node.data, end=" ")
if tmp_node.next == None:
break
tmp_node = tmp_node.next
print()
# Create Node as a Head node.
item01 = Node(10)
obj = SinglyLinkedList(item01)
obj.add(Node(20))
obj.add(Node(30))
obj.add(Node(40))
obj.print()

Error: Merge two sorted linkedlist using dummy head technique in Python

I'm trying to solve merge two sorted linkedlist problem using dummy head technique. For some reason I have an error coming from passing an argument to my dummy head holder. The output suppose to merge both linkedlist like this: 1-> 1-> 2-> 3-> 7-> None
I would be happy if you please guide which data needs to pass in my dummy head variable? Thanks in advance! This is the error I have:
dummy = LinkedList()
TypeError: __init__() missing 1 required positional argument: 'data
Here's my complete code:
class LinkedList:
def __init__(self, data):
self.data = data
self.next = None
def print_list(head: LinkedList) -> None:
while head:
print(head.data, end=" -> ")
head = head.next
print("None")
def merge_lists(headA, headB):
dummy = LinkedList()
curr = dummy
while headA != None and headB != None:
if headA.data < headB.data:
curr.next = headA
headA = headA.next
else:
curr.next = headB
headB = headB.next
curr = curr.next
if headA != None:
curr.next = headA
else:
curr.next = headB
return dummy.next
node1 = LinkedList(1)
node1.next = LinkedList(2)
node1.next.next = LinkedList(7)
node2 = LinkedList(1)
node2.next = LinkedList(3)
print(merge_lists(node1, node2)) # 1-> 1-> 2-> 3-> 7-> None
Since it is a dummy node, and you never ever use the data attribute of that node, you can pass anything as argument, like None:
dummy = LinkedList(None)
Alternatively, you could specify that providing an argument is optional, and define the constructor as follows:
class LinkedList:
def __init__(self, data=None):
self.data = data
self.next = None
Unrelated, but at the end of your script you have:
print(merge_lists(node1, node2))
This will print the object reference. You probably wanted to call the function you have defined for this purpose:
print_list(merge_lists(node1, node2))
If you want print to work like that, then instead of the print_list function, enrich LinkedList with an __iter__ method to ease iteration over the values in the list, and a __repr__ or __str__ method as follows:
class LinkedList:
def __init__(self, data=None):
self.data = data
self.next = None
def __iter__(self):
head = self
while head:
yield head.data
head = head.next
yield None # Optional
def __repr__(self):
return " -> ".join(map(str, self))
...and then you can do
print(merge_lists(node1, node2))
class node:
def __init__(self, data):
self.data = data
self.next = None
class linkedList:
def __init__(self):
self.head = None
def insertNode(self, data):
newnode = node(data)
if self.head is None:
self.head = newnode
else:
current = self.head
while current.next is not None:
current = current.next
current.next = newnode
def printLL(self):
current = self.head
while current.next is not None:
print(current.data, end='----->')
current = current.next
print(current.data, '------>None')
def sortLL(self):
arr=[]
current = self.head
while current.next is not None:
arr.append(current.data)
current = current.next
arr.append(current.data)
arr.sort()
self.head = None
for i in arr:
self.insertNode(i)
def mergeTwoSortedLL(l, l2):
current1 = l.head
current2 = l2.head
l3 = linkedList()
while current1 is not None and current2 is not None:
if current1.data < current2.data:
l3.insertNode(current1.data)
current1 = current1.next
else:
l3.insertNode(current2.data)
current2 = current2.next
if current1 is None:
while current2.next is not None:
l3.insertNode(current2.data)
current2 = current2.next
l3.insertNode(current2.data)
else:
while current1.next is not None:
l3.insertNode(current1.data)
current1 = current1.next
l3.insertNode(current1.data)
return l3
l = linkedList()
l.insertNode(9)
l.insertNode(18)
l.insertNode(11)
l.insertNode(15)
l.insertNode(1)
l.insertNode(8)
l.sortLL()
l.printLL()
l2 = linkedList()
l2.insertNode(9)
l2.insertNode(18)
l2.insertNode(11)
l2.insertNode(15)
l2.insertNode(1)
l2.insertNode(8)
l2.sortLL()
l2.printLL()
mergeTwoSortedLL(l,l2).printLL()

Node getting added twice into list

This is my code ignore if any of the spacing is wrong the code works perfectly fine in python.
class Node:
def __init__(self, value):
self.value = value
self.next = None
def __str__(self):
return "Node({})".format(self.value)
def getNext(self):
return self.next
def getValue(self):
return self.value
def setNext(self, new_next):
self.next = new_next
def setValue(self, new_value):
self.value = new_value
__repr__ = __str__
class OrderedLinkedList:
def __init__(self):
self.head=None
self.tail=None
self.count = 0
def __str__(self):
temp=self.head
out=[]
while temp:
out.append(str(temp.value))
temp=temp.next
out=' '.join(out)
return ('Head:{}\nTail:{}\nList:{}'.format(self.head,self.tail,out))
__repr__=__str__
def add(self, value):
#write your code here
if self.head == None:
new_node = Node(value)
self.head = new_node
self.tail = self.head
self.head.setNext(self.tail)
if self.head.value > value:
new_node = Node(value)
new_node.value = value
new_node.next = self.head
self.head = new_node
else:
new_node = Node(value)
self.tail.setNext(new_node)
self.tail = new_node
self.count += 1
def pop(self):
#write your code here
if self.head == None:
return 'List is empty'
if len(self) == 1:
value = self.head.getValue()
self.head = None
self.tail = None
self.count = 0
return value
current = self.head
while current.next is not self.tail:
current = current.getNext()
value = self.tail.getValue()
self.tail = current
self.tail.next = None
self.count -= 1
return value
def isEmpty(self):
#write your code here
return self.head == None
def __len__(self):
#write your code here
return self.count
The only problem I have with it is that when I first use the function add it adds the number twice. Below is the outcome when I first call add every time after that it adds the number only once. How can I fix it so it only adds the first number once instead of twice.
>>> x=OrderedLinkedList()
>>> x.add(2)
>>> print(x)
Head:Node(2)
Tail:Node(2)
List:2 2
add(item) adds a new Node with value=item to the list making sure that the ascending order is preserved. It needs the item and returns nothing.
Yep, it adds the first number twice since you need fix a bug in your add method by adding an elif:
def add(self, value):
if self.head == None:
new_node = Node(value)
self.head = new_node
self.tail = self.head
# self.head.setNext(self.tail) ## remove to prevent infinity loop
elif self.head.value > value:
new_node = Node(value)
new_node.value = value
new_node.next = self.head
self.head = new_node
else:
new_node = Node(value)
self.tail.setNext(new_node)
self.tail = new_node
Since, if the head es None once the data is added then the next conditional always will execute one of the two parts on if or else.

Remove method in Python LinkedList using an index

class Node(object):
def __init__(self, data, next):
self.data = data
self.next = next
class LinkedList(object):
head = None
tail = None
def print_list(self):
node = self.head
while node:
print node.data,
node = node.next
def add_front(self, data):
node = Node(data, None)
if self.head is None:
self.head = self.tail = node
else:
self.tail.next = node
self.tail = node
def remove(self, index):
curr_node = self.head
prev_node = None
while curr_node and index>=0:
if index == 0:
if prev_node is not None:
prev_node.next = curr_node.next
else:
self.head = curr_node.next
index = index - 1
prev_node = curr_node
curr_node = curr_node.next
So, I wanted to implement a remove method using index in python but it does not seem to be working. I think I'm messing something with replacing the nodes but can't figure out which one. So a little help needed here.

Python: binary search in linked list

Having homework with an assignment of implementing a linked list with a binary search method. Since linked lists are inherently linear, this does seem odd, however the idea is apparently to show that one is able to form the search method and connect it to the LL, essentialy just simulating binary search, since its complexity will not be better then that of linear. So far i have implemented a simple linked list, together with a working linear search method.
class Node:
def __init__(self, cargo):
self.cargo = cargo
self.next = None
def get_data(self):
return self.cargo
def get_next(self):
return self.next
class LinkedList:
def __init__(self):
self.head = None
self.tail = None
def add(self, cargo):
new_node = Node(cargo)
if self.head == None:
self.head = new_node
if self.tail != None:
self.tail.next = new_node
self.tail = new_node
def PrintList(self):
node = self.head
while node != None:
print(node.cargo)
node = node.next
def length(self):
current = self.head
count = 0
while current != None:
count = count + 1
current = current.get_next()
return count
def linSearch(self, cargo):
current = self.head
found = False
while current and found is False:
if current.get_data() == cargo:
found = True
else:
current = current.get_next()
return found
def binSearch(self, cargo):
LL = LinkedList
low = 0
high = LL.length(self)-1
while low <= high:
mid = (low+high)//2
if self[mid] > cargo:
high = mid-1
elif self[mid] < cargo:
low = mid+1
else:
return mid
return -1
LL = LinkedList()
LL.add(1)
LL.PrintList()
print(LL.linSearch(2))
print(LL.binSearch(1))
Current error when running the binSearch method is that object does not support indexing. Unfortunately, i’m stuck.

Categories

Resources