pop method LinkedList Class - python

I have implemented the LinkedList class: I need to implement the pop() which takes no parameter. The method removes and returns the item at the end of the linked list. If the list is empty it returns None and does nothing.
class LinkedList:
def __init__(self):
self.head = None
self.count = 0
def is_empty(self):
return self.count == 0
def size(self):
return self.count
def add(self, item):
new_node = Node(item)
new_node.set_next(self.head)
self.head = new_node
self.count += 1
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):
found = False
current = self.head
previous = None
while current != None and not found:
if current.get_data() == item:
found = True
else:
previous = current
current = current.get_next()
if found:
if previous == None:
self.head = current.get_next()
else:
previous.set_next(current.get_next())
self.count -= 1
else:
raise ValueError("remove(" + str(item) + "). " + str(item) + " is not in list")
def clear(self):
self.head = None
self.count = 0
def __str__(self):
temp = self.head
if(temp != None):
output ="Head"
while (temp != None):
output = output+" --> "+str(temp.data)
temp = temp.next
return output
else:
return "Head --> None"
def append(self, item):
new_node = Node(item)
if self.head is None:
self.head = new_node
return
last = self.head
while(last.next):
last = last.next
last.next = new_node
def pop(self): #Problem here
if self.head is None:
return None
else:
popnode = self.head
self.head = self.head.next
popnode.next = None
return popnode.data
Test:
a_list = LinkedList()
a_list.add(1)
a_list.add(2)
a_list.add(3)
print(a_list)
print("Removed item:",a_list.pop())
print("Removed item:",a_list.pop())
print(a_list)
Expected Output:
Head --> 3 --> 2 --> 1
Removed item: 1
Removed item: 2
Head --> 3
Recd Output:
Head --> 3 --> 2 --> 1
Removed item: 3
Removed item: 2
Head --> 1
Test:
a_list = LinkedList()
a_list.append(1)
a_list.append(2)
a_list.append(3)
print(a_list)
print("Removed item:",a_list.pop())
print("Removed item:",a_list.pop())
print(a_list)
Expected output:
Head --> 1 --> 2 --> 3
Removed item: 3
Removed item: 2
Head --> 1
Recd output:
Head --> 1 --> 2 --> 3
Removed item: 1
Removed item: 2
Head --> 3

Here's a simplified pop() method which does what you require -
def pop(self): #Problem here
# Empty LinkedList
if self.head is None:
return None
# There is a single node in the LinkedList = head, read data and delete it
if self.head.next is None:
data = self.head.data
self.head = None
return data
# there are 2 or more nodes in the LinkedList
secondlast = self.head
while (secondlast.next.next):
secondlast = secondlast.next
# found the second last node
# read the data of the last node and then delete it, by setting secondlast.next = None
data = secondlast.next.data
secondlast.next = None
return data
another approach using a temporary dummy node to simplify case when there is a single node in the LinkedList-
def pop(self): #Problem here
# Empty linkedlist
if self.head is None:
return None
# create a dummy secondlast node
secondlast = Node(-1)
secondlast.next = self.head
while (secondlast.next.next):
secondlast = secondlast.next
data = secondlast.next.data
secondlast.next = None
return data
In your LinkedList, both append() and pop() methods are O(n), since you need to traverse through whole LinkedList to do those operations. Consider adding a new property self.tail(or self.secondlast) to the LinkedList which keeps track of the last node in the LinkedList. It would help in simplifying the code and making both append() and pop() operations O(1)

Just track popnode.next when become None and at the same time store previous item, when popnode.next become None, Just put next of prev None, and return data of popnode.next:
def pop(self): # Problem here
if self.head is None:
return None
elif self.head.next == None:
d = self.head.data
self.head = None
return d
else:
popnode = self.head
prev = popnode
while popnode.next:
prev = popnode
popnode = popnode.next
prev.next = None
return popnode.data
The output of:
a_list = LinkedList()
a_list.add(1)
a_list.add(2)
a_list.add(3)
print(a_list)
print("Removed item:", a_list.pop())
print("Removed item:", a_list.pop())
print("Removed item:", a_list.pop())
print(a_list)
Will be:
Head --> 3--> 2--> 1
Removed item: 1
Removed item: 2
Removed item: 3
Head None

Related

Missed Print Line

I am trying to print the program so it will look like this.
Inserting 1
Inserting 2
Inserting 3
Top element is 3
Removing 3
Removing 2
Removing 1
The stack is empty
But when I run the program, I missed "Inserting 1".
My code look like this
class Node:
def __init__(self,data):
self.data = data
self.next = None
class Stack:
def __init__(self):
self.head = None
def isempty(self):
if self.head == None:
return True
else:
return False
def push(self,data):
if self.head == None:
self.head=Node(data)
else:
newnode = Node(data)
newnode.next = self.head
self.head = newnode
print("Inserting ", str(self.head.data))
def pop(self):
if self.isempty():
return None
else:
poppednode = self.head
self.head = self.head.next
poppednode.next = None
print("Removing",poppednode.data)
return poppednode.data
def peek(self):
if self.isempty():
return None
else:
return self.head.data
def display(self):
iternode = self.head
if self.isempty():
print("The stack is empty")
else:
while(iternode != None):
print(iternode.data,"->",end = "")
iternode = iternode.next
return
stack = Stack()
stack.push(1)
stack.push(2)
stack.push(3)
print("Top element is ",stack.peek())
stack.pop()
stack.pop()
stack.pop()
stack.display()
First time you push an item, self.head is None so the first block of code is executed. Unindent the print('Insert') line so it prints for both cases.
def push(self,data):
if self.head == None:
self.head = Node(data)
else:
newnode = Node(data)
newnode.next = self.head
self.head = newnode
print("Inserting ", str(self.head.data)) # <== unindent 1-level
When you are pushing the first time self.head will be None and it won't go in the else condition where it is printing "Inserting 1"

Delete last node in linked list

I am implementing deletion of last node in linked list using Python. Below is my code:
class Node:
def __init__(self, key):
self.key = key
self.next = None
def printList(head):
curr = head
while curr != None:
print(curr.key, end=" ")
curr = curr.next
def deleteLastNode(head):
if head == None:
return None
temp = head
# Iterating till the last Node
while temp.next != None:
temp = temp.next
temp = None
return head
# Driver code
head = Node(10)
head.next = Node(20)
head.next.next = Node(30)
head = deleteLastNode(head)
printList(head)
However, in output I'm still getting the complete linked list.
10 20 30
How is it printing 30 when the last node is already set to temp = None?
Well, your linked list is:
10 -> 20 -> 30
^head
Your iteration:
10 -> 20 -> 30
^head ^temp
Then when you do temp = None, just means(you just assign None to temp):
10 -> 20 -> 30 None
^head ^temp
A correct way is when you iterate on 20, do temp.next = None to remove the reference to the last node. So your code might be:
class Node:
def __init__(self, key):
self.key = key
self.next = None
def printList(head):
curr = head
while curr != None:
print(curr.key, end=" ")
curr = curr.next
def deleteLastNode(head):
if head == None:
return None
temp = head
# Iterating till the last Node
while temp.next.next != None:
temp = temp.next
temp.next = None
return head
# Driver code
head = Node(10)
head.next = Node(20)
head.next.next = Node(30)
head = deleteLastNode(head)
printList(head)
This code would work when your linked list contain at least two elements. When there is only one element, this will raise exception. I would recommend you use a dummy head node which next point to the real head node.
#Another way of solving
class Node:
def __init__(self, key):
self.key = key
self.next = None
def printList(head):
curr = head
while curr != None:
print(curr.key, end=" ")
curr = curr.next
def deleteLastNode(head):
if head == None:
return None
temp = head
prev=None #creating the value of previous element
# Iterating till the last Node
while temp.next != None:
prev=temp #updating for every iteration
temp = temp.next
prev.next = None #returning as NONE value
return head
# Driver code
head = Node(10)
head.next = Node(20)
head.next.next = Node(30)
head = deleteLastNode(head)
printList(head)

Remove Duplicates from unsorted Linked list(python)

In my last code for removing duplicates, the method removeDup isn't working.
The last print(ll.display()) is printing the previous linked list.
I was hoping it to print only unique nodes. What am I missing in removeDups method?
I can't figure out. What is happening in the code here?
class Node:
def __init__(self,data = None):
self.data = data
self.next = None
def __repr__(self):
return self.data
class LList:
def __init__(self):
self.head = None
def display(self):
current = self.head
node = []
while current != None:
node.append(current.data)
current = current.next
return node
def append(self, data):
elem = Node(data)
if self.head == None:
self.head = elem
else:
current = self.head
while current.next != None:
current = current.next
current.next = elem
def add_atFront(self, data):
elem = Node(data)
if self.head == None:
self.head = elem
else:
elem.next = self.head
self.head = elem
def removeDup(self):
current = self.head
previous = None
elems = []
while current != None:
if current.data in elems:
previous.next= current.next
else:
elems.append(current.data)
previous = current
current = current.next
ll= LList()
print(ll.display())
ll.append(65)
ll.append(7)
ll.add_atFront('65')
ll.add_atFront('Bare')
ll.insert('10',0)
ll.insert('7',2)
print(ll.display())
ll.removeDup()
print(ll.display())
Your removeDup works fine, the issue is that 65 and '65' are not duplicates, so you should not expect removeDup to dedup them. The same goes for 7 and '7'. Also, note you never defined the insert method, but I'll assume that's just a copy error.

Single Link List in Python Add, Remove, Insert

I'm trying to achieve a singly linked list with add, remove and insert methods. I'm confused with the insertion method.
class Node(object):
def __init__(self, data, next):
self.data = data
self.next = next
class SingleList(object):
head = None
tail = None
def printList(self):
print "Link List:"
current_node = self.head
while current_node is not None:
print current_node.data, " --> ",
current_node = current_node.next
print None
def add(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 insert(self, before, nextdata):
#nextdata is to be inserted before 'before'
#before is actually a data
#but it has dif name in this def to avoid confusion with 'data'
current_node = self.head
previous_node = None
while current_node is not None:
if current_node.data == before:
if previous_node is not None:
current_node.next = current_node
previous_node = current_node
current_node = current_node.next
def remove(self, node_value):
current_node = self.head
previous_node = None
while current_node is not None:
if current_node.data == node_value:
# if this is the first node (head)
if previous_node is not None:
previous_node.next = current_node.next
else:
self.head = current_node.next
# needed for the next iteration
previous_node = current_node
current_node = current_node.next
Link List:
1 --> 2 --> 3 --> 4 --> 5 --> None
Link List:
3 --> 4 --> 6 --> 10 --> None
For example if I'm trying to do insert (4,9) which inserts number 9 before 4.
s = SingleList()
s.add(1)
s.add(2)
s.add(3)
s.add(4)
s.add(5)
s.printList()
s.add(6)
s.add(10)
s.remove(5)
s.remove(2)
s.remove(1)
s.printList()
s.insert(4,9)
s.printList()
Any help will do, snippets, advice anything not spoon feeding. Thanks!
You have to rewrite your insert as:
def insert(self, before, nextdata):
#nextdata is to be inserted before 'before'
#before is actually a data
#but it has dif name in this def to avoid confusion with 'data'
current_node = self.head
previous_node = None
while current_node is not None:
if current_node.data == before:
if previous_node is not None:
temp_node = current_node
current_node = Node(nextdata, temp_node)
previous_node.next = current_node
else:
new_node = Node(nextdata, current_node)
self.head = new_node
break
previous_node = current_node
current_node = current_node.next
This will take care of it. When you insert the new node you have to break your loop otherwise it will be infinite.

Linked List in Python- Append, Index, Insert, and Pop functions. Not sure with code/errors

This assignment asks us to implement the append, insert, index and pop methods for an unordered linked-list.
(What I have so far)
def main():
class Node:
def __init__(self, data):
self.data = data
self.next_node = None
class LinkedList:
def __init__(self):
self.head = None
self.tail = None
def AppendNode(self, data):
new_node = Node(data)
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.data)
node = node.next
def PopNode( self, index ):
prev = None
node = self.head
i = 0
while ( node != None ) and ( i < index ):
prev = node
node = node.next
i += 1
if prev == None:
self.head = node.next
else:
prev.next = node.next
list = LinkedList()
list.AppendNode(1)
list.AppendNode(2)
list.AppendNode(3)
list.AppendNode(4)
list.PopNode(0)
list.PrintList( )
The output so far:
2
3
4
Traceback (most recent call last):
File "<pyshell#32>", line 1, in <module>
main()
File "<pyshell#31>", line 50, in main
list.PrintList( )
File "<pyshell#31>", line 27, in PrintList
node = node.next
AttributeError: 'Node' object has no attribute 'next'
I'm not sure why i'm getting the errors, since the code is technically working. Also any input on the insert, and index functions would be greatly appreciated.
For insert and index methods you will need another Node attribute, because you'll need to keep track of which item is on what position. Let we call it position. Your Node class will now look like this:
class Node:
def __init__(self, data, position = 0):
self.data = data
self.next_node = None
self.position = position
Retrieving index value now is easy as:
def index(self,item):
current = self.head
while current != None:
if current.data == item:
return current.position
else:
current = current.next
print ("item not present in list")
As for the list-altering methods, I would start with a simple add method which adds items to the leftmost position in the list:
def add(self,item):
temp = Node(item) #create a new node with the `item` value
temp.next = self.head #putting this new node as the first (leftmost) item in a list is a two-step process. First step is to point the new node to the old first (lefmost) value
self.head = temp #and second is to set `LinkedList` `head` attribute to point at the new node. Done!
current = self.head #now we need to correct position values of all items. We start by assigning `current` to the head of the list
self.index_correct(current) #and we'll write helper `index_correct` method to do the actual work.
current = self.head
previous = None
while current.position != self.size() - 1:
previous = current
current = current.next
current.back = previous
self.tail = current
What shall the index_correct method do? Just one thing - to traverse the list in order to correct index position of items, when we add new items (for example: add, insert etc.), or remove them (remove, pop, etc.). So here's what it should look like:
def index_correct(self, value):
position = 0
while value != None:
value.position = position
position += 1
value = value.next
It is plain simple. Now, let's implement insert method, as you requested:
def insert(self,item,position):
if position == 0:
self.add(item)
elif position > self.size():
print("position index out of range")
elif position == self.size():
self.AppendNode(item)
else:
temp = Node(item, position)
current = self.head
previous = None
while current.position != position:
previous = current
current = current.next
previous.next = temp
temp.next = current
temp.back = previous
current.back = temp
current = self.head
self.index_correct(current)
Below is the implementation that I could come up with (tested and working). It seems to be an old post, but I couldn't find the complete solution for this anywhere, so posting it here.
# add -- O(1)
# size -- O(1) & O(n)
# append -- O(1) & O(n)
# search -- O(n)
# remove -- O(n)
# index -- O(n)
# insert -- O(n)
# pop -- O(n) # can be O(1) if we use doubly linked list
# pop(k) -- O(k)
class Node:
def __init__(self, initdata):
self.data = initdata
self.next = None
def getData(self):
return self.data
def getNext(self):
return self.next
def setNext(self, newnext):
self.next = newnext
class UnorderedList:
def __init__(self):
self.head = None
self.tail = None
self.length = 0
def isEmpty(self):
return self.head is None
def add(self, item):
temp = Node(item)
temp.setNext(self.head)
self.head = temp
if self.tail is None:
self.tail = temp
self.length += 1
def ssize(self): # This is O(n)
current = self.head
count = 0
while current is not None:
count += 1
current = current.getNext()
return count
def size(self): # This is O(1)
return self.length
def search(self, item):
current = self.head
found = False
while current is not None and not found:
if current.getData() == item:
found = True
else:
current = current.getNext()
return found
def remove(self,item):
current = self.head
previous = None
found = False
while current is not None and not found:
if current.getData() == item:
found = True
else:
previous = current
current = current.getNext()
if previous == None:
# The item is the 1st item
self.head = current.getNext()
else:
if current.getNext() is None:
self.tail = previous # in case the current tail is removed
previous.setNext(current.getNext())
self.length -= 1
def __str__(self):
current = self.head
string = '['
while current is not None:
string += str(current.getData())
if current.getNext() is not None:
string += ', '
current = current.getNext()
string += ']'
return string
def sappend(self, item): # This is O(n) time complexity
current = self.head
if current:
while current.getNext() is not None:
current = current.getNext()
current.setNext(Node(item))
else:
self.head = Node(item)
def append(self, item): # This is O(1) time complexity
temp = Node(item)
last = self.tail
if last:
last.setNext(temp)
else:
self.head = temp
self.tail = temp
self.length += 1
def insert(self, index, item):
temp = Node(item)
current = self.head
previous = None
count = 0
found = False
if index > self.length-1:
raise IndexError('List Index Out Of Range')
while current is not None and not found:
if count == index:
found = True
else:
previous = current
current = current.getNext()
count += 1
if previous is None:
temp.setNext(self.head)
self.head = temp
else:
temp.setNext(current)
previous.setNext(temp)
self.length += 1
def index(self, item):
pos = 0
current = self.head
found = False
while current is not None and not found:
if current.getData() == item:
found = True
else:
current = current.getNext()
pos += 1
if not found:
raise ValueError('Value not present in the List')
return pos
def pop(self, index=None):
if index is None:
index = self.length-1
if index > self.length-1:
raise IndexError('List Index Out Of Range')
current = self.head
previous = None
found = False
if current:
count = 0
while current.getNext() is not None and not found:
if count == index:
found = True
else:
previous = current
current = current.getNext()
count += 1
if previous is None:
self.head = current.getNext()
if current.getNext() is None:
self.tail = current.getNext()
else:
self.tail = previous
previous.setNext(current.getNext())
self.length -= 1
return current.getData()
def insert(self,item,position):
if position==0:
self.add(item)
elif position>self.size():
print("Position index is out of range")
elif position==self.size():
self.append(item)
else:
temp=Node.Node(item,position)
current=self.head
previous=None
current_position=0
while current_position!=position:
previous=current
current=current.next
current_position+=1
previous.next=temp
temp.next=current
Notice that in the Node class you defined the "next" field as "next_node". Therefore the interpreter doesn't know "next". So, instead of node.next it should be node.next_node

Categories

Resources