LinkedList print and moving elements to another LinkedList - python

From list first I should do LinkedList and put elements into it (I did that). From that list I have to move all not string elements (integers) to another LinkedList and print them also.
Initialisation:
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList(object):
def __init__(self):
self.head = None
self.tail = None
self.size = 0
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):
last = last.next
last.next = new_node
def Lista(lista):
linked = LinkedList()
for element in lista:
linked.append(element)
return linked
Function for print and function(izdvoji) to move elements to another linkedlist:
def ispis(self):
temp = self.head
while (temp):
print (temp.data)
temp = temp.next
print("------")
def izdvoji(self):
linked = LinkedList()
temp = self.head
while(temp):
if isinstance (temp.data, str):
linked.append(temp.data)
temp = temp.next //edited
else:
temp = temp.next
if __name__ == '__main__':
L = Lista([33, "asp","oop1",5,21,"python",2,"c++"])
ispis(izdvoji(L))
ispis(L)
Result must be:
asp,oop1,python,c++
33,5,21,2
Sorry for long code but I want you to see it.
Edit function:
def izdvoji(linkedLista):
linked = LinkedList()
temp = linkedLista.head
while(temp != None):
if isinstance (temp.data, str):
linked.append(temp.data)
temp = temp.next
temp = linkedLista.head
while(temp != None):
if temp == linkedLista.head and isinstance (temp.data, str):
linkedLista.head = temp.next
print(temp.data)
if temp.next != None and isinstance (temp.next.data, str):
temp.next = temp.next.next
temp = temp.next
return linked
Output:
asp,oop1, python,c++,
33, oop1, 5, 21, 2,

The print function accepts an end parameter which defaults to "\n". You can it to be ", " to print your list.
To move your nodes from one list to another you need to do two steps
Copy the node to new list
Delete the node from old list
You did not have a delete method to handle that so I had to write delete method myself.
Delete method for linked list
def delete(self, node_data):
temp = self.head
# If list is empty
if temp is None:
return
# If the head need to be removed
if temp.data == node_data:
self.head = temp.next
return
# Iterate over the list and stops when the next node is our required node
while temp is not None and temp.next.data != node_data:
temp = temp.next
# if temp is none that means we reached the end of list
if temp is None:
return
# removing the node
temp.next = temp.next.next
def ispis(linked_list):
temp = linked_list.head
while (temp):
print(temp.data, end=", ")
temp = temp.next
print("\n------")
Output:
33, asp, oop1, 5, 21, python, 2, c++,
------
As far as copying goes. You forgot to update the temp when the if condition was true. Technically you don't need else here as well. You also need to return the list after moving the elements which you are not doing.
def izdvoji(linked_list):
linked = LinkedList()
temp = linked_list.head
while temp:
if isinstance(temp.data, str):
linked.append(temp.data) # Copy node to new list
linked_list.delete(temp.data) # delete from old list
temp = temp.next
return linked
Output:
asp, oop1, python, c++,
------
33, 5, 21, 2,
------
Main Code:
if __name__ == '__main__':
L = Lista([33, "asp","oop1",5,21,"python",2,"c++"])
ispis(izdvoji(L))
ispis(L)
Note: By convention self is only used for to refer the attributes and methods of the class. izdvoji and ispis are not class methods. So using self here makes no sense.

Related

Making a function to clone a linked list without using the copy function

class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
self.size = 0
# find a node which contains the data matching the input value
def findNode(self, value):
curr = self.head
while curr:
if curr.data == value:
return curr
curr = curr.next
return curr
# add a new node as the first node
def addNode(self, data):
newNode = Node(data) # create the new node
newNode.next = self.head
self.head = newNode
self.size+=1
# print the data in all the nodes
def printNode(self):
listprint = []
curr = self.head
while curr:
listprint.append(curr.data)
curr = curr.next
print(listprint)
#what i am trying to make
def duplicateLL(original):
newlist = LinkedList()
curr = original
if not curr:
return
while curr != None:
newlist.addNode(curr)
curr = curr.next
return newlist
#to test if function works
LLA = LinkedList()
for n in range(1,5):
LLA.addNode(n)
LLB = duplicateLL(LLA)
# modify LLA
curr = LLA.head
for n in range(LLA.size):
curr.data += 10
curr = curr.next
LLA.printNode()
LLB.printNode()
# driver code will be executed if this file is executed directly
# driver code will not be executed if this file is imported into another file
if __name__ == "__main__":
mylinkedlist = LinkedList()
for i in range(5):
mylinkedlist.addNode(2*i)
mylinkedlist.printNode()
I am trying to make a function duplicateLL, which is outside of the linked list class. Function duplicateLL is supposed to clone a linked list without using the built in copy function.
**** Note that I can only edit the function duplicateLL.***
The code prompts out: 'LinkedList' object has no attribute 'next'.
What am I doing wrong?
The outputs should be:
[14, 13, 12, 11]
[4, 3, 2, 1]
[8, 6, 4, 2, 0]
There was two problem for the duplicateLL function.
First, you tried to search through LinkedList which has no next attribute. Therefore, you need to use Node to travel through each element, so I assigned Node attribute to curr variable in duplicateLL function.
Second, you need to add the data of the node with the addNode function. I changed that part as well.
Here is the code:
def duplicateLL(original : LinkedList):
newlist = LinkedList()
curr = original.head
if not curr:
return
while curr != None:
newlist.addNode(curr.data)
curr = curr.next
return newlist.reverse()

I am trying to define a Linked list in Python, but why it is always going to add first element

class Node:
def __init__(self, data):
self.key = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
L1 = LinkedList()
print(L1.head)
def Insert(key,root):
temp = root
if (root != None):
while(temp.next):
temp = temp.next
temp.next = Node(key)
print("donr next")
else:
root = Node(key)
print("doneroot")
list1 = [1,2,3,4,5,6]
for i in range(0,len(list1)):
Insert(list1[i],L1.head)
def printing(ll):
temp = ll.head
print("printing")
print(temp)
while(temp):
print(temp.key)
temp = temp.next
printing(L1)
The ouput is:
None
doneroot
doneroot
doneroot
doneroot
doneroot
printing
None
Why it is always adding to the root element
In Python, everything is passed by reference. When the passed object is immutable, the label actually gets reassigned in its scope. For example:
def modify_a_list(x): # lists are mutable
x.append(1)
def modify_a_string(x): # strings are immutable
x += 'bar'
a = [3,2]
modify_a_list(a)
print(a) # gives [3, 2, 1]
b = 'text'
modify_a_string(b)
print(b) # prints 'text' and not 'textbar'.
In your example, when you pass L1.head as a parameter, it resolves to None and the newly defined label | variable named root inside you method reassigns to a new Node. But you wanted to assign it to attribute head of the linked list. This can be solved by passing the linked list as the parameter.
class Node:
def __init__(self, data):
self.key = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
L1 = LinkedList()
print(L1.head)
def Insert(key, ll):
temp = ll.head
if ll.head is not None:
while temp.next:
temp = temp.next
temp.next = Node(key)
print("donr next")
else:
ll.head = Node(key)
print("doneroot")
list1 = [1,2,3,4,5,6]
for i in range(0,len(list1)):
Insert(list1[i], L1)
def printing(ll):
temp = ll.head
print("printing")
print(temp)
while temp:
print(temp.key)
temp = temp.next
printing(L1)

Linked Lists: How to remove odd numbers?

I am currently taking an online computer science introductory course and have just learned the concept of a linked list. Though I understand the concept of linked lists, I still am unsure as how to deal with linked lists.
As such, I seek out help in solving the following problem, which will be of significant help for my understanding of linked lists:
Write a function (not in LinkedList class definition) that given a linked list, will change that linked list to filter out odd numbers. Immediately after the function returns, the linked list will only have even numbers.
I am unsure as to how to access the nodes in the list and check whether they are odd or even and remove or keep them accordingly.
I apologize if this seems like a trivial question, but I would appreciate any help that might help me learn.
The code for the linked list and node classes (as provided by the online course):
class Node:
def __init__(self, data=None, next_node=None):
self.data = data
self.next = next_node
def __str__(self):
return str(self.data)
class LinkedList:
def __init__(self):
self.length = 0
self.head = None
def print_list(self):
node = self.head
while node is not None:
print(node, end=' ')
node = node.next
print('')
def add_at_head(self, node):
node.next = self.head
self.head = node
self.length += 1
def remove_node_after(self, node):
if node.next is not None:
temp = node.next
node.next = node.next.next
temp.next = None
self.length -= 1
def remove_first_node(self):
if self.head is None:
return
temp = self.head
self.head = self.head.next
temp.next = None
self.length -= 1
def print_backward(self):
def print_nodes_backward(node):
if node.next is not None:
print_nodes_backward(node.next)
if node is not None:
print(node, end=' ')
if self.head is not None:
print_nodes_backward(self.head)
print('')
Let's say you have a bare-bones simple linked list that looks like this:
class LinkedList:
class ListNode:
def __init__(self, data):
self.data = data
self.next = None
def __init__(self):
self.head = None
def add(self, data):
if self.head is None:
self.head = LinkedList.ListNode(data)
else:
current_node = self.head
while current_node.next is not None:
current_node = current_node.next
current_node.next = LinkedList.ListNode(data)
def __str__(self):
ret = "["
current_node = self.head
while current_node is not None:
ret = ret + str(current_node.data)
if current_node.next is not None:
ret = ret + ", "
current_node = current_node.next
ret = ret + "]"
return ret
In other words, the LinkedList contains a single head, which is a ListNode. Every element in the Linked List is contained in a ListNode, and each ListNode points towards the next element in the list.
As you can see, for adding an element to the list, we either create a node at the head if the list is empty (i.e. self.head is None), or we traverse to the end of the list by continuously jumping to the .next element for each ListNode, starting from the head. We also use this paradigm for printing a string representation of our list.
So, to remove any node from the linked list, we can simply change the node that references it, so that the node we want to remove gets skipped. At which point it will disappear.
To remove all list nodes containing odd-numbered data, we might do something like this:
def remove_odds(self):
# special case: head node
# remove odd head elements by simply setting head to the next element after
while (self.head is not None) and (self.head.data % 2 == 1):
self.head = self.head.next
# regular case: the rest of the nodes
current_node = self.head
while (current_node is not None) and (current_node.next is not None):
# if the next node's data is odd, then
if current_node.next.data % 2 == 1:
# skip that node by pointing this node's .next to the next node's .next
current_node.next = current_node.next.next
# otherwise, move forwards in the list
else:
current_node = current_node.next
Proof of concept:
>>> lst = LinkedList()
>>> lst.add(2)
>>> lst.add(5)
>>> lst.add(6)
>>> lst.add(3)
>>> lst.add(7)
>>> lst.add(8)
>>> lst.add(10)
>>> lst.add(1)
>>> lst.add(4)
>>> print(lst)
[2, 5, 6, 3, 7, 8, 10, 1, 4]
>>> lst.remove_odds()
>>> print(lst)
[2, 6, 8, 10, 4]
Copied from comment: The idea is to iterate through the list head-to-tail while remembering the previous node; when you find a garbage node, apply remove_node_after to the remembered node, or move the head to the current node if we haven't had time to remember anything yet.
The code would be something like this (untested):
class LinkedList:
# ...
def delete_if(self, pred):
prev = None
curr = self.head
while curr:
if pred(curr.data):
if prev:
self.remove_node_after(prev)
else:
self.head = curr
prev = curr
curr = curr.next
llist.delete_if(lambda x: x % 2 == 1) # delete if odd
# Mahmoud AL-Mokdad
# this course on Udemy By SEfactoru right๐Ÿ˜
# use my code ๐Ÿ˜‰
def filter_even(ll):
first_node = ll.head
while (first_node is not None) and (first_node.data % 2 != 0):
ll.remove_first_node()
first_node = ll.head
node = first_node
while node is not None and node.next is not None:
if node.next.data % 2 != 0:
ll.remove_node_after(node)
else:
node = node.next

Merging Multiple sorted linkedlists into One

I am trying to write a program to merge two sorted linked lists.
But its not merging them.
it seems like the error is in representing head pointer.
how to represent head pointer? is my way correct.
I am facing a lot of problems using pointers pls give me some suggestions especially head pointer
merge two sorted linkedlist
class Node:
def __init__(self,data):
self.data=data
self.next =None
class linkedlist:
def __init__(self):
self.head=None
def push(self,ndata):
nnode = Node(ndata)
nnode.next = self.head
self.head = nnode
def addNodeToList(self,ndata):
nnode = Node(ndata)
if self.head is None:
self.head = nnode
return
last = self.head
while last.next is not None:
last = last.next
last.next = nnode
def printList(self):
temp = self.head
while temp is not None:
print(temp.data,end = ' ')
temp = temp.next
def merge(first,second):
dummy=linkedlist()
temp = dummy.head
temp1=first.head
temp2=second.head
while temp1 and temp2:
if temp1.data<temp2.data:
temp=temp1
temp.next=None
temp1=temp1.next
print('\n1..')
elif temp1.data>=temp2.data:
temp=temp2
temp.next=None
temp2=temp2.next
print('\n2..')
if temp1 is not None:
temp.next= temp1
print('\n3..')
else:
temp.next=temp2
print('\n4..')
print('Done')
return dummy
if __name__=='__main__':
list1=linkedlist()
list1.addNodeToList(10)
list1.addNodeToList(20)
list1.addNodeToList(30)
list1.addNodeToList(40)
list1.addNodeToList(50)
list2=linkedlist()
# Create linked list 2 : 5->15->18->35->60
list2.addNodeToList(5)
list2.addNodeToList(15)
list2.addNodeToList(18)
list2.addNodeToList(35)
list2.addNodeToList(60)
list1.printList()
print()
list2.printList()
a=merge(list1,list2)
a.printList()
Expected output is a single merged linkedlist
You already have the addNodeToList() function so why not use it?
def merge(first,second):
dummy=linkedlist()
temp1=first.head
temp2=second.head
while temp1 and temp2:
if temp1.data<temp2.data:
dummy.addNodeToList(temp1.data)
temp1=temp1.next
else:
dummy.addNodeToList(temp2.data)
temp2=temp2.next
while temp1:
dummy.addNodeToList(temp1.data)
temp1=temp1.next
while temp2:
dummy.addNodeToList(temp2.data)
temp2=temp2.next
return dummy
You are never adding to dummy in your code - you do temp = dummy.head and then you reassign temp and the dummy list is never updated. Here is an approach:
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList: # classes in python must be in CamelCase
def __init__(self):
self.head = None
def push(self, ndata):
nnode = Node(ndata)
nnode.next = self.head
self.head = nnode
def addNodeToList(self, ndata):
nnode = Node(ndata)
if self.head is None:
self.head = nnode
return
last = self.head
while last.next is not None:
last = last.next
last.next = nnode
def printList(self):
temp = self.head
while temp is not None:
print(temp.data, end = ' ')
temp = temp.next
def walk_list(self):
temp = self.head
values = []
while temp is not None:
values.append(temp.data)
temp = temp.next
return values
def merge(first, second):
values1 = first.walk_list()
values1.extend(second.walk_list())
dummy = LinkedList()
for v in sorted(values1):
dummy.push(v)
return dummy
if __name__ == '__main__':
list1 = LinkedList()
list1.addNodeToList(10)
list1.addNodeToList(20)
list1.addNodeToList(30)
list1.addNodeToList(40)
list1.addNodeToList(50)
list2 = LinkedList()
# Create linked list 2 : 5->15->18->35->60
list2.addNodeToList(5)
list2.addNodeToList(15)
list2.addNodeToList(18)
list2.addNodeToList(35)
list2.addNodeToList(60)
list1.printList()
print()
list2.printList()
a = merge(list1, list2)
a.printList()

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

Categories