Find the frequency of numbers using linkedlist - python

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.

Related

How do I remove node in Linked List?

I am implementing Linked List by using Python. Here is my code
class Node:
def __init__(self, value):
self.value = value
self.next = None
class LinkedList:
def __init__(self, head = None):
self.head = head
def append(self, newElement):
current = self.head
if self.head:
while current.next:
current = current.next
current.next = newElement
else:
self.head = newElement
#get position time complexity O(n)
#get the node at a specific position
def get_position(self, position):
current = self.head
current_pos = 1
while current_pos <= position:
if current_pos == position:
return current
current = current.next
current_pos += 1
return None
#Insert element
# Time complexity O(n)
def insert_element(self, element, position):
if position > 1:
front_pos = self.get_position(position - 1)
end_pos = self.get_position(position + 1)
front_pos.next = element
element.next = end_pos
else:
element.next = self.head
self.head = element
def delete_element(self, element):
current = self.head
previous = None
while current:
if current.value == element:
if not previous:
self.head = element
previous.next = current.next
else:
current = current.next
previous = current
else:
return False
node1 = Node("Iron Man")
node2 = Node("Capitain America")
node3 = Node("Doctor Strange")
node4 = Node("Spider man")
node5 = Node("Rieder")
print("Node1 Value is {}".format(node1.value))
print("Node1 next Value is {}".format(node1.next))
print("Node2 Value is {}".format(node2.value))
print("Node2 next Value is {}".format(node2.next))
Avengers = LinkedList()
Avengers.append(node1)
print("Firt element in link list is {}".format(Avengers.head.value))
Avengers.append(node2)
print("After Iron Man is {}".format(Avengers.head.next.value))
print(Avengers.get_position(2).value)
Avengers.append(node3)
Avengers.append(node4)
Avengers.insert_element(node5, 4)
print(Avengers.get_position(4).value)
Avengers.delete_element(node5)
print(Avengers.get_position(4).value)
Here is my output:
Node1 Value is Iron Man
Node1 next Value is None
Node2 Value is Capitain America
Node2 next Value is None
Firt element in link list is Iron Man
After Iron Man is Capitain America
Capitain America
Rieder
Rieder
The list structure link like this: Ironman -> Capitain America -> Doctor Strange -> Rieder -> Spiderman
Therefore, if I do not want the "Rieder" node. The last line of output should show "Spider man"
What happened in my code? Really appreciate for people who help me out :D
One issue is that you appear to update current and then update previous with the new value of current. I would go back to your delete method, and go through it line by line. It helps if you write out on paper what the state of your list is at each line, and see if you can correct the algorithm.
else:
current = current.next
previous = current
First you need to fix your insert_element function. You are inserting nodes incorrectly. This is the correct way to do it
def insert_element(self, element, position):
if position > 1:
front_pos = self.get_position(position - 1)
# end_pos should not be position + 1, because it will
# skip the element at index=position
end_pos = self.get_position(position)
front_pos.next = element
element.next = end_pos
else:
element.next = self.head
self.head = element
Next, you need to only pass the value of the nodes and not the nodes themselves while deleting the elements. I have made some minor changes to your code to fix some bugs. See the comments for more information
def delete_element(self, element):
current = self.head
previous = None
while current:
if current.value == element:
# This means that the head itself
# has to be deleted
if not previous:
self.head = self.head.next
# Add an else block correctly here
# in case head is not to be deleted
else:
previous.next = current.next
# break the loop when the element is deleted
break
else:
# First copy the current into previous,
# Then change the value of current
previous = current
current = current.next
Also there is no need for else: return False block at the end of delete function.

How to avoid starvation in a priority queue

I am trying to create a queue that avoids having elements in the queue for too long. I am using a linked list. The way I want to implement it is that if a greater priority is added, the ones that are pushed backed have 0.4 added to them. I also need to implement a sort for the linked list but that makes some sense already. I do not really understand how I am supposed to add this 0.4 to the priority's that have been displaced.
class Node:
def __init__(self, data=None):
self.data = data
self.next = None
class LinkedList:
def __init__(self,):
self.head = Node()
def append(self, data):
new_node = Node(data)
current = self.head
while current.next is not None:
current = current.next
current.next = new_node
def __str__(self):
data = []
current = self.head
while current is not None:
data.append(current.data)
current = current.next
return "[%s]" %(', '.join(str(i) for i in data))
def __repr__(self):
return self.__str__()
def length(self):
current = self.head
total = 0
while current.next is not None:
total += 1
current = current.next
return total
def display(self):
elements = []
current_node = self.head
while current_node.next is not None:
current_node = current_node.next
elements.append(current_node.data)
print("Elements ", elements)
def get(self, index):
if index >= self.length():
print("Error: Index is out of range!")
return None
current_index = 0
current_node = self.head
while True:
current_node = current_node.next
if current_index == index:
return current_node.data
current_index += 1
def remove(self):
current = self.head
if current is not None:
self.head = current.next
else:
print("Queue is empty!")
def main():
queue = LinkedList()
queue.append(5)
queue.append(2)
queue.display()
main()
I'd suggest using python's heapq rather than a linked list. Because you're doing a custom comparison, you'll probably want to implement something like what's described in heapq with custom compare predicate.
In addition to the priority, add a field that contains the time when the item was added to the heap. Then, your actual priority is a function of the assigned priority and the length of time the item has been in the heap. For example, the priority could be something like:
elapsed_time = current_time - added_time;
real_priority = assigned_priority * elapsed_time;
You might want to make the multiplier some fraction of the elapsed time.
Another possibility is if you want to make sure that something doesn't stay in the queue longer than some set time. For example, if you want to make sure things don't stay for more than 5 minutes, you could add dequeue_time field. Your comparison then becomes something like:
// assume items a and b are being compared
if (a.dequeue_time < current_time) {
if (b.dequeue_time < a.dequeue_time) {
// b sorts before a
}
else if (b.dequeue_time > a.dequeue_time) {
// return a sorts before b
}
else { // dequeue times are equal
return result of comparing a.priority to b.priority
}
}
else {
// here, return result of comparing a.priority and b.priority
}
heapq is going to be much more efficient than your linked list, especially as the number of items in your queue increases. Plus, it's already written and known working. All you have to do is provide the comparison function.

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

Creation of a Linked List

I am trying to created a linked list. However, the following code keeps printing only the last element of the list. Is there an error in my code? I think the problem lies in the "insert" method. I am not able to figure out why though.
import sys
import io
string = """4
2
3
4
1"""
sys.stdin = io.StringIO(string)
class Node:
def __init__(self, data):
self.data = data
self.next = None
class Solution:
def display(self, head):
current = head
while current:
print(current.data, end=' ')
current = current.next
# TODO: Code only prints the last element of data
def insert(self, head, data):
if head == None:
head = Node(data)
return head
else:
head.next = Node(data)
return head.next
mylist = Solution()
T = int(input())
head = None
for i in range(T):
data = int(input())
head = mylist.insert(head, data)
mylist.display(head)
The problem is you're losing the reference to the head of the list. You must keep the head and insert the new item at the end of the list
def insert(self,head,data):
if head == None:
head = Node(data)
else:
current = head
while current.next != None:
current = current.next
current.next = Node(data)
return head
You only keep a reference to the end of the chain (head.next), so yes, you'll only be able to display that last element.
You'll need to keep a reference to the first element (the real head):
mylist = Solution()
T = int(input())
current = head = None
for i in range(T):
data = int(input())
current = mylist.insert(head, data)
if head is None:
head = current

Linkedlist Remove Duplicates without buffer

I am trying to implement an algorithm to remove duplicates from a linkedlist but my algorithm freeze when it comes to check if the current node has data equal with the next one.
class Node:
def __init__(self, data, next):
self.data = data
self.next = next
class LinkedList:
def __init__(self, head = None):
self.head = head
def add(self, item):
newNode = Node(item, self.head)
self.head = newNode
def printit(self):
current = self.head
while current is not None:
print(current.data)
current = current.next
def removeDuplicates(self):
current = self.head
while current != None:
runner = current
while runner.next != None:
if runner.next.data == current.data:
runner.next = current.next.next
else:
runner = current.next
current = current.next
mylist = LinkedList()
mylist.add(31)
mylist.add(77)
mylist.add(31)
mylist.add(22)
mylist.add(22)
mylist.add(22)
mylist.printit()
mylist.removeDuplicates()
mylist.printit()
It is maybe really silly, but I can't spot it right now, any ideas?
In your while loop:
runner = current.next
should be
runner = runner.next
otherwise it just keeps taking the same current.next on each iteration, since it never changes current in the loop. Same fix a couple of lines earlier.

Categories