Inserting Node at given position - python

I am learning python and data structure. I was implementing singly linked list methods which included inserting at head and at given position. I ended up writing this code :
class Node :
def __init__(self,data=None,next_node=None) :
self.data = data
self.next = next_node
class LinkedList :
def __init__(self) :
self.head = None
def insertathead(self,new_data) :
new_node = Node(new_data)
new_node.next = self.head
self.head = new_node
def InsertNpos(self,new_data,pos):
start = self.head
if pos == 0:
return Node(new_data, self.head)
while pos > 1:
self.head = self.head.next
pos -= 1
self.head.next = Node(new_data, self.head.next)
return start
def PrintLinkList(self) :
temp = self.head
while (temp) :
print (temp.data)
temp = temp.next
if __name__ == '__main__' :
llist = LinkedList()
llist.insertathead(8)
llist.insertathead(3)
llist.insertathead(10)
llist.insertathead(12)
llist.insertathead(15)
llist.insertathead(2)
llist.InsertNpos(1,2)
llist.PrintLinkList()
Output:
15
1
12
10
3
8
Now, just inserting at head works fine but InsertNpos(1,2) gives wrong output. The output is supposed to be 2,15,1,12,10,3,8.Please tell me where my code is wrong.

When you insert at position pos, your insertion routine deletes the first pos-1 elements of the list. It changes the head pointer on each iteration. You need a local variable to iterate through the list. Also, why are you returning a value? You never use it. The only purpose of this method is to update the list in place.
def InsertNpos(self,new_data,pos):
if pos == 0:
self.head = Node(new_data, self.head)
return
start = self.head
while pos > 1:
start = start.next
pos -= 1
start.next = Node(new_data, start.next)
New output:
Before insertion
2
15
12
10
3
8
After insertion
2
15
1
12
10
3
8

Even though the answer has already been accepted, I tried the solution and as AChampion suggested it didn't work for me for inserting at 0, but my solution did:
class Node :
def __init__(self,data=None,next_node=None) :
self.data = data
self.next = next_node
class LinkedList :
def __init__(self) :
self.head = None
def insertathead(self,new_data) :
new_node = Node(new_data)
new_node.next = self.head
self.head = new_node
def InsertNpos(self,new_data,pos):
if pos == 0:
self.head = Node(new_data, self.head)
return self.head
i = 0
curr = self.head
while curr.next:
if i == pos - 1:
curr.next = Node(new_data, curr.next)
return self.head
curr = curr.next
i += 1
curr.next = Node(new_data)
return self.head
def PrintLinkList(self) :
temp = self.head
while (temp) :
print (temp.data)
temp = temp.next
This will insert the item at the end if pos is out of range.

def insertNodeAtPosition(head, data, position):
current = head
if not head:
head = SinglyLinkedListNode(data)
return head
# Shift to element before position i.e. before_node
# Change it to point to new_node
# Set new_node.next to before_node.next
for _ in range(position-1):
current = current.next
temp = current.next
new_node = SinglyLinkedListNode(data)
current.next = new_node
new_node.next = temp
return head

Related

Linked List-Singly linked list .......why do we use location == 1?

#While I was studying linked list, i came across a doubt. I could not understand while adding a node or removing a node from the end the location was 1.Can anyone help me out?
#Why location == 1 for adding/ removing from end side?
#Please explain !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
class Node:
def __init__(self, value=None):
self.value = value
self.next = None
class SLinkedList:
def __init__(self):
self.head = None
self.tail = None
def __iter__(self):
node = self.head
while node:
yield node
node = node.next
# insert in Linked List
def insertSLL(self, value, location):
newNode = Node(value)
if self.head is None:
self.head = newNode
self.tail = newNode
else:
if location == 0:
newNode.next = self.head
self.head = newNode
elif location == 1:
newNode.next = None
self.tail.next = newNode
self.tail = newNode
else:
tempNode = self.head
index = 0
while index < location - 1:
tempNode = tempNode.next
index += 1
nextNode = tempNode.next
tempNode.next = newNode
newNode.next = nextNode
def deleteNode(self, location):
if self.head is None:
print("The SLL does not exist")
else:
if location == 0:
if self.head == self.tail:
self.head = None
self.tail = None
else:
self.head = self.head.next
elif location == 1:
if self.head == self.tail:
self.head = None
self.tail = None
else:
node = self.head
while node is not None:
if node.next == self.tail:
break
node = node.next
node.next = None
self.tail = node
else:
tempNode = self.head
index = 0
while index < location - 1:
tempNode = tempNode.next
index += 1
nextNode = tempNode.next
tempNode.next = nextNode.next
Inserting at the beginning and end have to be treated specially.
To insert at the beginning you assign the head attribute of the list rather than the next attribute of the previous node (because there is no previous node).
When you insert at the end, you have to update the tail attribute of the list in addition to linking it to the old tail via its next attribute.

How to retrieve the first added node when a LinkedList is created?

I have created a linkedlist in Python using below classes:
class: Node
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
class LinkedList:
def __init__(self):
self.head = None
def insert_at_beginning(self, data):
temp = Node(data)
if self.head is None:
self.head = temp
else:
temp.next = self.head
self.head = temp
def insert_at_end(self, data):
temp = Node(data)
if self.head is None:
self.head = temp
else:
curr = self.head
while curr.next is not None:
curr = curr.next
curr.next = temp
def insert_at_position(self, pos, data):
temp = Node(data)
if self.head is None:
self.head = temp
else:
curr = self.head
i = 1
while i < pos:
curr = curr.next
i += 1
temp.next = curr.next
curr.next = temp
def traverse_list(self):
if self.head is None:
print('List is empty')
else:
curr = self.head
while curr.next is not None:
print(curr.data)
curr = curr.next
Below is the order I am calling the insertion methods.
ll = LinkedList()
ll.head = Node(1)
ll.insert_at_beginning(data=10)
ll.insert_at_beginning(data=11)
ll.traverse()
The elements printed in the output are: 11 & 10 which are the ones I inserted but I don't see the value 1 which is a node I added in the beginning.
Is there any logic I missed here that is making the first value skip or not being considered ?
Your problem comes from while curr.next is not None: in traverse_list(). Assuming you're pointing your last node, its next node is obviously None. Therefore, it will stop the loop before printing the last node's data.
You can try this:
def traverse_list(self):
if self.head is None:
print('List is empty')
else:
curr = self.head
while curr is not None:
print(curr.data)
curr = curr.next

How do I fix the adding value in middle of linked list location?

I'm creating a single linked list insert beginning, end, and middle of the linked list. After running code inserting the middle is not working in the linked list changing location value randomly and after running it's not getting.
Can anyone suggest what is wrong with the code:
class Node:
def __init__(self, value=None):
self.value = value
self.next = None
class SLinkedList:
def __init__(self):
self.head = None
self.tail = None
def __iter__(self):
node = self.head
while node:
yield node
node = node.next
def insertsll(self, value, location):
new_node = Node(value)
if self.head is None:
self.head = new_node
self.tail = new_node
else:
if location == 0:
new_node.next = self.head
self.head = new_node
elif location == 1:
new_node.next = None
self.tail.next = new_node
self.tail = new_node
else:
temp_node = self.head
index = 0
while index < location - 1:
temp_node = temp_node.next
index += 1
next_node = temp_node.next
temp_node.next = new_node
new_node.next = next_node
# if temp_node == self.tail:
# self.tail = new_node
sll = SLinkedList()
sll.insertsll(1, 1)
sll.insertsll(2, 1)
sll.insertsll(3, 1)
sll.insertsll(4, 1)
sll.insertsll(0, 0)
sll.insertsll(60, 3)---> run this random changing location not working in correct location
sll.insertsll(50, 4)---> run this random changing location not working in correct location
print([node.value for node in sll])
Output:
[0, 1, 50, 2, 3, 4]
Process finished with exit code 0
I think the iteration in the while loop was a little bit too complicated. I think with this code it is more understandable what the insert does. Also, I don't know why you had the location === 1 check. It seems to be not necessary.
class Node:
def __init__(self, value=None):
self.value = value
self.next = None
class SLinkedList:
def __init__(self):
self.head = None
self.tail = None
def __iter__(self):
node = self.head
while node:
yield node
node = node.next
def insertsll(self, value, location):
new_node = Node(value)
if self.head is None:
self.head = new_node
self.tail = new_node
else:
if location == 0:
new_node.next = self.head
self.head = new_node
else:
temp_node = self.head
index = 0
# Iterate to insert location
while index < location - 1:
index += 1
temp_node = temp_node.next
# Insert new node
new_node.next = temp_node.next
temp_node.next = new_node
# Check if new node is tail
if new_node.next is None:
self.tail = new_node
sll = SLinkedList()
sll.insertsll(1, 1)
sll.insertsll(2, 1)
sll.insertsll(3, 1)
sll.insertsll(4, 1)
sll.insertsll(0, 0)
sll.insertsll(60, 3)
sll.insertsll(50, 4)
print([node.value for node in sll])
Output:
[0, 1, 4, 60, 50, 3, 2]
P.S.: Such a structure really benefits from a length attribute. This can be used to check if an insert operation is even allowed. Probably, you should consider adding it.

Implementing a LinkedList in Python - Is leetcode wrong?

I'm working on this problem: https://leetcode.com/explore/learn/card/linked-list/209/singly-linked-list/1290/
and leetcode is telling me that my code is throwing a runtime error. The input it's trying to make my code run is this:
["MyLinkedList","addAtHead","deleteAtIndex","addAtHead","addAtHead","addAtHead","addAtHead","addAtHead","addAtTail","get","deleteAtIndex","deleteAtIndex"]
[[],[2],[1],[2],[7],[3],[2],[5],[5],[5],[6],[4]]
Where the first array contains the function name and the second contains the function parameters. E.g. the second element adds a 2 at the head of the linkedlist. My question is that how would it be OK to be deleting the element at index 1 when there is only one element in the linkedlist? Is there some special thing about linked lists that I should know or is the input case incorrect. Below is my code for reference.
class SinglyLinkedList():
def __init__(self):
self.head = None
self.tail = None
self.length = 0
def get(self, index):
if index<0 or index>self.length: raise AssertionError("get index must be in bounds")
node = self.head
for _ in range(index):
node = node.next
return node
def addAtHead(self, val):
node = SinglyListNode(val)
if self.length==0:
self.head = node
self.tail = self.head
else:
node.next = self.head
self.head = node
self.length+=1
def addAtTail(self, val):
node = SinglyListNode(val)
if self.length==0:
self.tail = node
self.head = self.tail
else:
self.tail.next = node
self.tail = node
self.length+=1
def addAtIndex(self, index, val):
if index<0 or index>self.length:
raise AssertionError(f"index at which to add ({index}) is out of bounds")
if index==0:
return self.addAtHead(val)
if index==self.length:
return self.addAtTail(val)
newNode = SinglyListNode(val)
node = self.head
for _ in range(index-1):
node = node.next
newNode.next = node.next
node.next = newNode
self.length+=1
def deleteAtIndex(self, index):
if index<0 or index>self.length:
raise AssertionError(f"index at which to add ({index}) is out of bounds")
if index==0:
self.head = self.head.next
elif index==self.length-1:
self.tail=self.get(self.length-2)
else:
node = self.head
for _ in range(index-1):
node = node.next
node.next = node.next.next
self.length-=1
def __str__(self):
res = "["
node = self.head
for _ in range(self.length-1):
res += str(node)+","
node = node.next
res += str(node)+f"] ({self.length})"
return res
From https://leetcode.com/problems/design-linked-list/
void deleteAtIndex(int index) Delete the indexth node in the linked list, if the index is valid.
Looks like the delete needs to be done only when the index is valid. Your code needs to handle the case when the index is invalid.

why the element not appending in linked list?

not getting expected output. Missing node with data = 6
looks like not insertAfter method properly,
cant find the issue.
pls suggest any other issue too as i am just started with data structures. is there anything need to be kept in mind while studying data structures.
class Node:
def __init__(self,data):
self.data = data
self.next = None
class LinkeList:
def __init__(self):
self.head = None
def push(self,new_data):
new_node = Node(new_data)
new_node.next = self.head
self.head = new_node
def insertAfter(self,prev_node,new_data):
new_node = Node(new_data)
if self.head is None:
self.head = new_node
return
new_node.next = prev_node.next
prev_node.next = new_node
def append(self,new_data):
new_node = Node(new_data)
if self.head is None:
self.head = new_node
return
last = self.head
while last.next != None:
last = last.next
last.next = new_node
def printList(self):
temp = self.head
while temp is not None:
print(temp.data, end = " ")
temp = temp.next
if __name__ =='__main__':
llist = LinkedList()
llist.append(7)
llist.append(8)
llist.push(5)
llist.insertAfter(Node(5),6)
llist.printList()
So the issue is in this line,
llist.insertAfter(Node(5),6)
When you do insertAfter then you need to first get a Node from the current linked list, rather what you are doing is, that you create a new node, then pass it. That new node might have the same value as a . node in your linked list, but it really isn't a part of it, what you need to do is as follows
First implement a get node function, that gets a node from the linked list with the value that you want, something like this
def getNode(self, value):
temp = self.head
while temp is not None:
if temp.value == value:
return temp
else:
temp = temp.next
return None
then do this.
llist.insertAfter(llist.getNode(5),6)
Also put a check for if passed node is not None in insertAfter

Categories