How to add a node to a linked list? - python

I'm creating a function that takes in a sorted linked list and a value. I create a new node with the given value by new_node = LN(v). I am trying to return a linked list with the new node in the correct position. The example will help clarify.
Ex)
ll = converts_list_to_linked_list([4, 7, 9, 14]) #I have a linked list: 4->7->9->12->14
The Function:
insert_ordered(ll, 12)
returns a linked list of "4->7->9->12->14->None"
I am completely stuck on how to insert the new node in the correct position. The last else statement in my function is incorrect.
def insert_ordered(ll,x):
new_node = LN(v) #Creates new node
#If given ll is empty, newnode is the linkedlist
if ll == None:
ll = new_node
#Makes new_node the head of ll if first val is >= new_node value.
elif ll.value >= new_node.value:
temp = ll
ll = new_node
ll.next = temp
#[ERROR] Adds new_node between two nodes of ll in sorted order.
else:
while ll.next != None:
if ll.value < new_node.value:
ll = ll.next
new_node.next = ll.next
ll.next = new_node
return ll
After solving this iteratively, is it possible to solve it recursively?

Try this:
class LN:
def __init__(self, value):
self.value = value
self.next = None
def insert_ordered(root, data):
node = LN(data)
if root == None:
return node
else:
if root.value > data:
node.next = root
return node
else:
temp, prev = root, None
while temp.next and temp.value <= data:
prev = temp
temp = temp.next
if temp.next == None and temp.value <= data:
temp.next = node
else:
node.next = prev.next
prev.next = node
return root
root = None
root = insert_ordered(root, 4)
root = insert_ordered(root, 7)
root = insert_ordered(root, 9)
root = insert_ordered(root, 14)
root = insert_ordered(root, 12)
#4->7->9->12->14

Related

How to fix 'NoneType' has no attribute 'key', when trying to compare a key value to a string

I am writing a program where the user inputs a postfix expression and it outputs the answer. Current I am stuck when Using my 'evaluate' function within my for loop.
Inside my For loop Main.py:
else:
# Debug Code
print('{}: Else'.format(i))
print('{}: Length'.format(len(stack)))
Node.right = stack.pop()
Node.left = stack.pop()
Node = TreeNode(str(i))
stack.push(str(i))
# Debug Code
print('{}: Right Key'.format(Node.right))
print('{}: Left Key'.format(Node.left))
print('{}: Node Key'.format(Node.key))
print('{}: Node Key Type'.format(type(Node.key)))
Node = evaluate(Node)
stack.push(int(Node))
I am getting the error below:
Traceback (most recent call last):
File "c:\Users\dpr48\main.py", line 49, in <module>
Node = evaluate(Node)
File "c:\Users\dpr48\main.py", line 10, in evaluate
return evaluate(node.left) + evaluate(node.right)
File "c:\Users\dpr48\main.py", line 9, in evaluate
if node.key == '+':
AttributeError: 'NoneType' object has no attribute 'key'
So my question is why is it not using the 'TreeNode' class to get the key value? As well as the line of code that should define the 'Node.left' as the 'stack.pop()' value and 'Node.right' as the 'stack.pop()' value ends up not changing either of them and leaves them as None, as found in the 'Debug Code' that I have implemented to see what the program is doing interenally.
Provided each class used below:
Main.py
from Stack import Stack
from TreeNode import TreeNode
def evaluate(node):
if node.key == '+':
return evaluate(node.left) + evaluate(node.right)
elif node.key == '-':
return evaluate(node.left) - evaluate(node.right)
elif node.key == '*':
return evaluate(node.left) * evaluate(node.right)
elif node.key == '/':
return evaluate(node.left) / evaluate(node.right)
else:
return node.key
stack = Stack()
exp = "23+"
list = [*exp]
for i in list:
if i.isdigit() is True:
# Debug Code
print('{}: True'.format(i))
Node = TreeNode(int(i))
stack.push(int(i))
else:
# Debug Code
print('{}: Else'.format(i))
print('{}: Length'.format(len(stack)))
Node.right = stack.pop()
Node.left = stack.pop()
Node = TreeNode(str(i))
stack.push(str(i))
# Debug Code
print('{}: Right Key'.format(Node.right))
print('{}: Left Key'.format(Node.left))
print('{}: Node Key'.format(Node.key))
print('{}: Node Key Type'.format(type(Node.key)))
Node = evaluate(Node)
stack.push(int(Node))
print(evaluate(stack.node))
Stack.py
from Node import Node
from LinkedList import LinkedList
class Stack:
def __init__(self):
self.list = LinkedList()
def push(self, new_item):
# Create a new node to hold the item
new_node = Node(new_item)
# Insert the node as the list head (top of stack)
self.list.prepend(new_node)
def pop(self):
# Copy data from list's head node (stack's top node)
popped_item = self.list.head.data
# Remove list head
self.list.remove_after(None)
# Return the popped item
return popped_item
def __len__(self):
node = self.list.head # Start at head of stack to count until stack returns Null
count = 0
while node != None:
node = node.next
count+=1
return count # Returning length of stack
LinkedList.py
class LinkedList:
def __init__(self):
self.head = None
self.tail = None
def append(self, new_node):
if self.head == None:
self.head = new_node
self.tail = new_node
else:
self.tail.next = new_node
self.tail = new_node
def prepend(self, new_node):
if self.head == None:
self.head = new_node
self.tail = new_node
else:
new_node.next = self.head
self.head = new_node
def insert_after(self, current_node, new_node):
if self.head == None:
self.head = new_node
self.tail = new_node
elif current_node is self.tail:
self.tail.next = new_node
self.tail = new_node
else:
new_node.next = current_node.next
current_node.next = new_node
def remove_after(self, current_node):
# Special case, remove head
if (current_node == None) and (self.head != None):
succeeding_node = self.head.next
self.head = succeeding_node
if succeeding_node == None: # Remove last item
self.tail = None
elif current_node.next != None:
succeeding_node = current_node.next.next
current_node.next = succeeding_node
if succeeding_node == None: # Remove tail
self.tail = current_node
Node.py
class Node:
def __init__(self, initial_data):
self.data = initial_data
self.next = None
TreeNode.py
class TreeNode:
# Constructor assigns the given key, with left and right
# children assigned with None.
def __init__(self, key):
self.key = key
self.left = None
self.right = None
There are several issues:
Node is the name of a class, yet you use the same name for a TreeNode instance, shadowing the class name. This is not the main problem, but certainly not advised. Related: Don't use PascalCase for instances, but camelCase. So node, not Node.
You assign to Node.right when you have not yet defined Node yet, which happens later with Node = TreeNode(str(i)). You should first assign to Node (well, better node) and only then assign to its attributes.
With Node.right = stack.pop() you clearly expect the stack to contain TreeNode instances, but with stack.push(str(i)) you push strings. That will lead to the problems you describe. The stack should not be populated with strings, but with TreeNode objects.
At the end of the else block you call evaluate, and then push that result value to the stack. This is wrong and should be removed. The evaluation should only happen when you have completed the tree, and it should not involve the stack. The stack has a role in building the tree, not in evaluating it.
The final print line makes an access to stack.node, but stack has no node attribute. You'll want to pop the top item from the stack, which (if the input syntax was correct) should only have 1 node left on it, representing the root of the tree.
Not a problem, but i is guaranteed to be a string (with length 1), so there is no need to call str on it.
Here is the corrected code:
for i in list:
if i.isdigit() is True:
node = TreeNode(int(i)) # lowercase name
stack.push(node) # don't push string, but object
else:
node = TreeNode(i) # First create the node
node.right = stack.pop() # Then assign to its attributes
node.left = stack.pop()
stack.push(node) # don't push string
# Don't evaluate here, nor push anything else to the stack
print(evaluate(stack.pop()))

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.

How to recursively add a node to a linked list?

I created a function that inserts a node to its correct position.
For example:
root = converts_list_to_linked_list([4, 7, 9, 14]) #I have a linked list: 4->7->9->14
The Function:
insert_ordered(root, 12)
returns a linked list of "4->7->9->12->14->None"
class LN:
def __init__(self, value):
self.value = value
self.next = None
def insert_ordered(root, data):
node = LN(data)
if root == None:
return node
else:
if root.value > data:
node.next = root
return node
else:
temp, prev = root, None
while temp.next and temp.value <= data:
prev = temp
temp = temp.next
if temp.next == None and temp.value <= data:
temp.next = node
else:
node.next = prev.next
prev.next = node
return root
Is there any way to solve this problem recursively? I can't grasp the idea on how too.
Try this:
class LN:
def __init__(self, value, node=None):
self.value = value
self.next = node
def insert_ordered(root, data):
if root == None or root.value > data:
return LN(data, root)
root.next = insert_ordered(root.next, data)
return root
If you want to insert in descending order change root.value > data to root.value < data
The following uses an auxiliary function to recursively insert into the list:
class LN:
def __init__(self, value):
self.value = value
self.next = None
def insert_ordered(self, data):
node = LN(data)
return self.insert_ordered_aux(node)
def insert_ordered_aux(self,node):
if self.value >= node.value: # add node before current node
node.next = self
return node
elif self.next: # do the recursion
self.next = self.next.insert_ordered_aux(node)
return self
else: # add node at end of list
self.next = node
return self
#test:
root = LN(4)
root = root.insert_ordered(9)
root = root.insert_ordered(14)
root = root.insert_ordered(6)
root = root.insert_ordered(-2)
root = root.insert_ordered(12)
def print_list(node):
if (node):
print(node.value)
print_list(node.next)
print_list(root)
How are you using it, and is your pasted code's indentation correct?
After some indentation adjustments, this is how i use it, and what i get:
class LN:
def __init__(self, value):
self.value = value
self.next = None
def insert_ordered(root, data):
node = LN(data)
if root == None:
return node
else:
if root.value > data:
node.next = root
return node
else:
temp, prev = root, None
while temp.next and temp.value <= data:
prev = temp
temp = temp.next
if temp.next == None and temp.value <= data:
temp.next = node
else:
node.next = prev.next
prev.next = node
return root
#Use:
a1 = LN(1)
a1.next = a2 = LN(5)
a2.next = a3 = LN(10)
a3.next = a4 = LN(15)
root = a1
#Insert tests
root = root.insert_ordered(13)
root = root.insert_ordered(12)
root = root.insert_ordered(15)
root = root.insert_ordered(-5)
root = root.insert_ordered(17)
t = root
while(t):
print(str(t.value) + " ")
t = t.next
Output:
-5
1
5
10
12
13
15
15
17

Insert after another item in linked list in python

I am trying to insert an item after another one but my code doesn't work. The below function insert_after_another doesn't work.
class LinkedList:
def __init__(self):
self.head = None
def insert_end(self,data):
x = Node(data)
if self.head == None:
self.head = x
return
temp = self.head
while(temp.next != None):
temp = temp.next
temp.next = x
def insert_after_another(self,old_data,new_data):
t_old = Node(old_data)
d_new = Node(new_data)
temp = self.head
while(temp):
if temp.data == old_data:
d_new.next = t_old.next
t_old.next = d_new
temp = temp.next
class Node:
def __init__(self,data):
self.data = data
self.next = None
if __name__=='__main__':
llist = LinkedList()
llist.insert_end(3)
llist.insert_end(32)
llist.insert_after_another(3,13)
I am not getting any result when I try to print the data.
d_new.next = t_old.next
in this line t_old.next pointing to nothing nor there is a pointer to it, it is just a node you created before.
def insert_after_another(self,old_data,new_data):
d_new=Node(new_data)
temp=self.head
while(temp):
if temp.data==old_data:
d_new.next = temp.next
temp.next = d_new
break
This may work I think.
You just need two swaps only,
The new node should point the old node's next and
the old node should point to the new one.
This will be able to resolve your problem. Consider having correct identations and renaming your method.
def insert_after_value(self, old_data, new_data):
if self.head is None:
return
if self.head.data == old_data:
self.head.next = Node(new_data, self.head.next)
return
temp = self.head
while temp:
if temp.data == old_data:
temp.next = Node(new_data, temp.next)
break
temp = temp.next

Inserting Node at given position

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

Categories