Merge Two Sorted Lists Python - python

I'm trying to solve merge sorted linked list problem.For that i've created three method. addlast , print and merge For linked list class created a three objects obj and obj1 (To create two linked list) Using obj3 calling a merge method by passing both linked list head pointer.But here it only print linked list 1 instead of both.
My expected result should be creating both linked list and print the sorted linked list.So what could be the reason the my code isn't working ?
class node:
def __init__(self,data) :
self.data = data
self.next = None
class linkedlist:
def __init__(self) :
self.head = None
def addlast(self,data):
newnode = node(data)
if self.head == None:
self.head = newnode
else:
current = self.head
while(current.next != None):
current = current.next
current.next = newnode
def print(self):
current = self.head
while(current):
print(current.data, "-->",end="")
current = current.next
print("NUll")
def merge(self,obj,obj1):
current = obj.head
current2 = obj1.head
newnode = node(None)
while current and current2 != None:
if (current == None):
newnode.next = current2
break
if (current2 == None):
newnode.next = current
break
if current.data <= current2.data:
newnode.next = current
current = current.next
print(newnode.data)
newnode = newnode.next
else:
newnode.next = current2
current2 = current2.next
print(newnode.data)
newnode = newnode.next
if current:
newnode.next = current
if current2:
newnode.next = current2
print(newnode.data)
obj = linkedlist()
obj.addlast(10)
obj.addlast(20)
obj.addlast(30)
obj.addlast(40)
obj1 = linkedlist()
obj1.addlast(50)
obj1.addlast(60)
obj1.addlast(70)
obj1.addlast(80)
obj3 = linkedlist()
obj3.merge(obj,obj1)

There are several issues in your code:
You created merge as an instance method, but never use self. If the intention is to merge a second list into the current list (self), then you need only one argument, i.e. the "other" list, not two.
merge should set the head attribute of the list that gets the merge result, i.e. self.head should be assigned a reference.
newnode progresses through the merged list, but your code loses track of what was the first node of that merged list, so you need an extra name so that you can later assign to self.head
if (current == None) is never going to be a true condition, as the while condition requires that both current and current2 are not None. The same goes for if (current2 == None): it will never be true.
The code to link the only remaining list (the last two if statements) should be put after the loop, not inside it. Only after the loop it is certain that one of current or current2 is None. Also that code can be simplified with the use of the or operator.
The reason you only see part of the merged list printed, is that you don't print the nodes that are appended ("in bulk") in that last operation.
Here is the corrected code:
def merge(self, obj1): # Only need one argument, not two
current = self.head # Use self
current2 = obj1.head
dummy = newnode = node(None) # keep track of this dummy node
while current and current2:
if current.data <= current2.data:
newnode.next = current
current = current.next
else:
newnode.next = current2
current2 = current2.next
newnode = newnode.next # This is common to both if/else case
newnode.next = current or current2 # out of the loop
self.head = dummy.next # update current list's head reference
The calling code should have near the end:
obj.merge(obj1)
obj.print()

This links the 2 lists Studrec and Aves then sort Studrec pulling the corresponding items from Ave.
def revert(Studrec, Ave):
Studrec, Ave = map(list, zip(*sorted(zip(Studrec, Ave), key=lambda x: x[0])))
return Studrec, Ave
Studrec, Ave = revert (Studrec, Ave)

In the merge function you're not updating the self.head, instance variable your code is merging the list but you're not keeping track of the head. Modify your code merge function to point the self.head to new node:
def merge(self,obj,obj1):
current = obj.head
current2 = obj1.head
newnode = node(None)
self.head=newnode

Related

Python : I am not able to prepend a Value in a Singly Linked list

Code written in python:
prepend Function is supposed to add a value to the start of the Linked List
display Function is supposed to display the linked list in a List format in python
fromarr Function is supposed to add new nodes to the linked list
class Node:
def __init__(self,value=None):
self.value = value
self.next = None
class SinglyLL:
def __init__(self):
self.head = Node()
self.tail = Node()
def prepend(self,value):
newnode = Node(value)
newnode.next = self.head
self.head = newnode
def append(self,data):
newnode = Node(data)
if self.head is None:
self.head = newnode
return
cur = self.head
while cur.next != None:
cur = cur.next
cur.next = newnode
newnode.next = None
def display(self):
lis = []
cur = self.head
while cur.next != None:
cur = cur.next
lis.append(cur.value)
return lis
def fromarr(self,list):
for i in list:
temp = Node(i)
self.append(temp.value)
newsll = SinglyLL()
newsll.fromarr([1,2,3,4,5])
newsll.prepend(10)
print(newsll.display())
Expected output : [10,1,2,3,4,5]
Actual Output: [None,1,2,3,4,5]
well you are initalising your head with a empty node, and displaying values from self.head.next, so instead of setting element at position 0 you need to set element at position 1.
Adding below code for prepend method
class Node:
def __init__(self,value=None):
self.value = value
self.next = None
class SinglyLL:
def __init__(self):
self.head = Node()
self.tail = Node()
def prepend(self,value):
newnode = Node(value)
if self.head is None:
self.head = newnode
else:
tmp = self.head.next
self.head.next = newnode
newnode.next = tmp
def append(self,data):
newnode = Node(data)
if self.head is None:
self.head = newnode
return
cur = self.head
while cur.next != None:
cur = cur.next
cur.next = newnode
newnode.next = None
def display(self):
lis = []
cur = self.head
while cur.next != None:
cur = cur.next
lis.append(cur.value)
return lis
def fromarr(self,list):
for i in list:
temp = Node(i)
self.append(temp.value)
newsll = SinglyLL()
newsll.fromarr([1,2,3,4,5])
newsll.prepend(10)
print(newsll.display())
Your code has a mix of several approaches to organise a linked list data structure, but they are not compatible:
Your constructor creates a dummy node for the head attribute, which could be an approach when you intend to append all data nodes after that dummy node. The display method is in line with that approach as it doesn't include the value of the dummy node in the result. But the prepend nor the append method use that approach as they treat the head node as a data node.
Your constructor creates a dummy node for the tail attribute. This is an approach that might be used for a doubly linked list, but is not useful for a singly linked list, as the process to append a new node at the end of the list cannot take benefit from this reference.
Although the constructor defines a tail attribute none of the other methods make use of it, nor update it when necessary.
Some other remarks:
It is odd that the display method does not display anything. It would be more appropriate to have an __iter__ method instead which would yield the linked list's values.
fromarr is not a very good name for a method that accepts a list.
It is not intuitive that this is an instance method, as its name suggests that it will create a new list from those values, but you actually need to first create a linked list instance yourself, and then call this method. I would suggest to drop this method and extend the constructor with optional arguments which will be used to populate the constructed linked list.
list is a bad name for a parameter as this name is already in use by native Python.
It would be nice if the Node constructor would accept an optional argument for defining the next attribute.
Here is an update of your code that takes those points into account, and which uses the approach where:
A tail attribute is set and used
No dummy nodes are created
class Node:
def __init__(self, value=None, nxt=None):
self.value = value
self.next = nxt
class SinglyLL:
def __init__(self, *values):
# Don't create nodes here
self.head = self.tail = None
# Allow immediate population from arguments
for value in values:
self.append(value)
def prepend(self,value):
self.head = Node(value, self.head)
self.tail = self.tail or self.head
def append(self, data):
if not self.tail:
self.prepend(data)
else:
self.tail.next = self.tail = Node(data)
def __iter__(self):
cur = self.head
while cur:
yield cur.value
cur = cur.next
newsll = SinglyLL(1,2,3,4,5)
newsll.prepend(10)
print(list(newsll)) # [10, 1, 2, 3, 4, 5]

Find the frequency of numbers using linkedlist

Find the frequency of numbers using linkedlist.
Getting SIGTSTP - time limit exceed error while running the below code. Can anyone help me where am I getting it wrong?
class Element(object):
def __init__(self,value):
self.value = value
self.next = None
class LinkedList(object):
def __init__(self, head = None):
self.head = head
def append(self, new):
current = self.head
if self.head:
while current.next:
current = current.next
current.next = new
else:
self.head = new
def traverse(self):
current = self.head
while current != None:
print(current.value)
current = current.next
arr = list(map(int, input().split()))
ll = LinkedList()
for i in arr:
e = Element(i)
ll.append(e)
ll.traverse()
def frequency(a):
current = a.head
while current != None:
count = 1
while current.next != None:
if current.value == current.next.value:
current+=1
if current.next.next != None:
current.next = current.next.next
else:
current.next = None
print(str(current.value)+" : " + str(count))
current = current.next
frequency(ll)
Everything looks fine except frequency. You will need to keep two references, one to the current element and the other will traverse the remainder of the list, starting from current. Does that give you something to go on?
Note too that your current implementation will modify the underlying linked list, while you can indeed do "skipping" with the pointers to prevent listing the same element multiple times, it is imo preferable to avoid modifying the underlying structure in this way.

Python linked list remove duplicate

I am trying to write a code to remove duplicates from a sorted linked list "head". My code below always returns the last duplicate if the list ends with a duplicate. for e.g. [1,2,2,3,3] will return [1,2,3,3]. I can't figure out why. Does anyone have an idea?
class Solution(object):
def deleteDuplicates(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if not head:
return head
l1=newhead=ListNode(head.val)
head=head.next
while head:
if head.val!=l1.val:
l1.next=head
l1=l1.next
head=head.next
return newhead
You should keep track of the leading node of each new value and keep fetching the next node until you get a node with a different value, at which point you assign that node as the next node for the leading node:
class Solution(object):
def deleteDuplicates(self, head):
node = head
while node:
lead = node
while node.next and node.next.val == lead.val:
node = node.next
node = lead.next = node.next
return head
Problem Solution
Create a class Node with instance variables data and next.
Create a class LinkedList with instance variables head and last_node.
The variable head points to the first element in the linked list while last_node points to the last.
Define methods append, get_prev_node, remove and display.
The method append takes a data item as argument and appends a node with that data item to the list.
The method get_prev_node takes a reference node as argument and returns the previous node. It returns None when the reference node is the first node.
The method remove takes a node as argument and removes it from the list.
The method display traverses the list from the first node and prints the data of each node.
Define a function remove_duplicates which takes a linked list as argument and removes duplicates from it.
The function remove_duplicates uses two nested loops to remove duplicate nodes.
Create an instance of LinkedList, remove duplicate nodes and display the list.
Program/Source Code
Here is the source code of a Python program to remove duplicates from a linked list.
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
self.last_node = None
def append(self, data):
if self.last_node is None:
self.head = Node(data)
self.last_node = self.head
else:
self.last_node.next = Node(data)
self.last_node = self.last_node.next
def get_prev_node(self, ref_node):
current = self.head
while (current and current.next != ref_node):
current = current.next
return current
def remove(self, node):
prev_node = self.get_prev_node(node)
if prev_node is None:
self.head = self.head.next
else:
prev_node.next = node.next
def display(self):
current = self.head
while current:
print(current.data, end = ' ')
current = current.next
def remove_duplicates(llist):
current1 = llist.head
while current1:
data = current1.data
current2 = current1.next
while current2:
if current2.data == data:
llist.remove(current2)
current2 = current2.next
current1 = current1.next
a_llist = LinkedList()
data_list = input('Please enter the elements in the linked list: ').split()
for data in data_list:
a_llist.append(int(data))
remove_duplicates(a_llist)
print('The list with duplicates removed: ')
a_llist.display()
Program Explanation
An instance of LinkedList is created.
The user is prompted to enter the data items for the list.
The function remove_duplicates is called to remove duplicates from the list.
The linked list is displayed.

Delete Middle Node in Python [from a purely C background]

I have been playing around with Python more recently due to its power and syntax. I've decided to make a linked list from https://www.tutorialspoint.com but with my strong background in C and being use to its manual memory allocation as well as having pointers for one the delete middle function is somewhat confusing to me. I know that objects makes references to other objects and variables and that the Python interpreter automatically handles this:
class Node:
def __init__(self, data=None):
self.data = data
self.next = None
class SLinkedList:
def __init__(self):
self.head = None
def printlist(self):
cur = self.head
while cur is not None:
print(cur.data)
cur = cur.next
def insertAtHead(self, newdata):
NewNode = Node(newdata) #create new node
newNode.next = self.head #create its .next to point to the current node
self.head = newNode #set its .next to point the current head
#creates a linked list with 3 elements
def createOneTwoThree(self):
list = SLinkedList()
list.head = Node('Mon')
e2 = Node('Tues')
e3 = Node('Wed')
list.head.next = e2
e2.next = e3
#function to add at the end of a linked list
def insertAtEnd(self, newdata):
newNode = Node(newdata)#create new node
if self.head = newNode:#if empty insert the thing
self.head = newNode
return
laste = self.head
while(last.next):
last = last.next
last.next = newNode
def inBetween(self, middle_node,newdata):
if middle_node is None:
print('Error 0: The mentioned node is absent')
return
newNode = Node(newdata)
newNode.next = middle_node.next
middle_node.next = newNode
def delete(self, removeKey):
headVal = self.head
if(head is not None):
if (head.data == removeKey):
break
prev = head
head = None
while(head is not None):
if head.data == removeKey:
break
prev = head
head = head.next
if (head == None):
return
prev.next = head.next
head = None
#Link Firt node to second node: list1.head.next = n2*******
I just fail to see what's going on here from a memory point of view that justifies it finding the in-between two said values and having them linked together. I am still new to Python and its classes and structures but from an intuitive aspect the inBetween method makes little sense to me though I see it's most underlying logic. Can someone more versed in Python please explain to my WHY this is happening and what exactly is going on with the objects, references and pointers?

Algorithm to delete a node from the middle

I'm reading Cracking the Coding Interview and doing practice problems and I'm stuck on this one:
"Implement an algorithm to delete a node in the middle (i.e., any node but the first and the last node, not necessarily the exact middle) or a singly linked list, given only access to that node.
EXAMPLE
Input: the node from the linked list a->b->c->d->e->f
Result: nothing is returned, but the new linked list looks like a->b->d->e->f"
Here's my code :
class Node:
def __init__(self, data = None, nextnode = None):
self.data = data
self.nextnode = nextnode
def __str__(self):
return str(self.data)
class LinkedList():
def __init__(self, head = None):
self.head = head
def insert(self, data):
new_node = Node(data)
new_node.nextnode = self.head
self.head = new_node
def remove(self, data):
current = self.head
absent = True
if current == None: print('List is empty')
if current.data == data:
self.head = current.nextnode
absent = False
while current.nextnode:
if current.nextnode.data == data:
absent = False
if current.nextnode.nextnode:
current.nextnode = current.nextnode.nextnode
else: current.nextnode = None
else: current = current.nextnode
if absent: print('Element not in list')
def size(self):
current = self.head
size = 0
while current:
current = current.nextnode
size += 1
return size
def find(self, data):
current = self.head
if current == None: print('List is empty')
search = True
while current and search:
if current.data == data:
print(current)
search = False
current = current.nextnode
if search: print('Not found')
def print_list(self):
current = self.head
while current:
print(current, end = ' ')
current = current.nextnode
print('')
node1 = Node(1)
node2 = Node(2)
node3 = Node(3)
node4 = Node(4)
node1.nextnode = node2
node2.nextnode = node3
node3.nextnode = node4
list1 = LinkedList(node1)
list1.insert(2 ****EDITED node2 to 2 here****)
print_list(list1)
def delmid(ll, n):
current = ll.head
if current == n:
print('Can\'t delete first node')
return
while current.nextnode:
if current.nextnode == n:
if current.nextnode.nextnode:
current.nextnode = current.nextnode.nextnode
return
else:
print('Can\'t delete last node')
return
delmid(list1, node2)
print_list(list1)
I can't figure out why it doesn't seem to think that ll.head and node2 are the same ... It does work if I get rid of the line list1.insert(node2) ...
I don't understand ...
EDIT: after reading the first sentence of the solution in the book, apparently i did it wrong anyways .... "given only access to that node" means you don't know the head of the list ... back to the drawing board ...
Because your insert method is wrong:
def insert(self, data):
new_node = Node(data)
new_node.nextnode = self.head
self.head = new_node
Your method does not insert node2 itself as a node: it creates a new node with node2 as payload (data). That is something different.
You can define a method:
def insert_node(self, node):
node.nextnode = self.head
self.head = new_node
Nevertheless this will create a loop since now node1 will be pointing to node2 and node2tonode1`. So the resulting linked list will be a rounded list with two elements, like:
node1 --> node2
^---------/
EDIT: since you solved that one. There is also a problem with your delmid method.
The main problem is that in your while loop you need to walk through the linked list, and you do not do that: current always remains the same, so:
def delmid(ll, n):
current = ll.head
if current == n:
print('Can\'t delete first node')
return
while current.nextnode:
if current.nextnode == n:
if current.nextnode.nextnode:
current.nextnode = current.nextnode.nextnode
return
else:
print('Can\'t delete last node')
return
current = current.nextnode
Should fix that.
Insert operation
You misunderstood your own insert-implementation.
list1.insert(node2) inserts a new node with node2 as content:
def insert(self, data):
new_node = Node(data) # <== wrap node2 into another node instance
new_node.nextnode = self.head
self.head = new_node
Comparison of Nodes
The ==-operator internally works by calling the method __eq__(self, other). In your case you didn't provide and implementation for this method, so the default is used to compare by all variables, which includes nextnode. Thus two nodes can only be equal, if they are precisely the same. To get this corrected, use a custom comparison method in Node:
def __eq__(self, other):
return type(other) is Node && other.data == self.data
This __eq__-method would work by first checking that other definitely is of type Node and afterwards compare by the data stored in each instance.
Delmid
Going a bit further than the actual question:
while current.nextnode:
if current.nextnode == n:
if current.nextnode.nextnode:
current.nextnode = current.nextnode.nextnode
return
else:
print('Can\'t delete last node')
return
This loop will run infinitely, unless the list has at most a size of 1. To fix this step through the list by current = current.nextnode.
Improving Delmid
The actual purpose of this task was to get you used to another way of manipulating linked lists: swapping.
Instead of searching the entire list for the predecessor of n, you could just check that n is neither the first nor the last node, swap out the value with the value of it's consecutive node and delete the consecutive node:
def delmid(ll, n):
if ll.head == n:
print('Can\'t delete first node')
return
if n.nextnode is None:
print('Can\'t delete last node')
return
# swap values
tmp = n.data
n.data = n.nextnode.data
n.nextnode.data = tmp
# remove node
n.nextnode = n.nextnode.nextnode

Categories