Linked list not working properly? - python

This is supposed to be a linked list which is gets a new node every time a line from a file runs through the loop. This is only a part of my code, but everything else works fine, so I didn't think it was relevant to include all of it.
The problem I'm having is that the nodes aren't being added properly. If I put print(head) and print(head['next']) immediately after this, it prints the correct information for the head node, but for head['next'] it prints "None", even when enough lines have run through the program for head['next'] to have data in it.
I followed instructions that I found for creating a linked list, but I must have done something wrong. I'm just not sure what it is.
if data[0] == "submit":
node = {}
node['data'] = data
head = node
head['next'] = None
if len(data) > 1:
if data[1] > "101":
newNode = {}
newNode = head['next']

The main problem is that you wrote:
newNode = head['next']
on the last line, and it should be:
head['next'] = newNode
So that the head dictionary links to the newNode.
Furthermore the data[1] > "101" is suspicious, since it will perform lexicographical comparison, instead of a numerical one.
You can probably rewrite your script to:
if data[0] == "submit":
# why do you assign the entire list as 'data'?
node = {'data': data, 'next': None}
head = node
if len(data) > 1 and int(data[1]) > 101: # numerical comparison?
newNode = {}
head['next'] = newNode
newNode['data'] = data[1] # assign second element?

without seeing more of your code, you forgot to assign the old head to this new node
node = {}
node["data"] = data # Sets data.
node["next"] = None # sets the next to none because there is no next as the head.
head["next"] = node # set the current heads next variable to this new node.
head = head["next"] # shift head to the new node by doing this.
Im a fan of more Object oriented code though, and while there is a war between Object oriented code vs scripts, this is a good spot to define classes etc and just make it more clean as you are already creating objects and assigning static keys.
Here is a simple class i put together:
class Node:
__init__(self, data):
self.data = data
self.next = None
set_next(self, node):
self.next = node
class LL:
__init__(self):
self.start = None
self.end = None
self.current = None
appendNode(self, node):
self.end.set_next(node)
self.end = self.end.next
appendData(self, data):
self.appendNode(new Node(data))
walk_list(self):
self.current = self.start
while self.current is not None:
yield self.current
self.current = self.current.next

Related

How do I connect an existing singly-linked-list and a new singly-linked-list in python?

def connect(self, new_sll):
pre = self.head
if sll is SinglyLL():
pre = self.head
for i in range(self.nodenumber):
pre = pre.next
if pre == None :
for i in range(i + new_sll.nodenumber):
aft = pre.next
new = sll.head.data
node = Node(new)
node.next = aft
pre.next = node
self.nodenumber +=1
else :
raise TypeError("error")
I'm trying to connect an existing singly-linked-list (sll) and another singly-linked-list (new_sll).
If new_sll's class type is SinglyLL, I want to connect new_sll with the existing sll and renew the node's number.
If new_sll's class type is not SinglyLL, I want to show a type error
I can't solve this matter... how can I fix my code?
There are several issues in your code:
sll is SinglyLL() can never be true, as SinglyLL() creates a new list, which obviously is not the one that sll represents.
Assuming that nodenumber is the number of nodes in the list, the condition pre == None is always going to be true, but then aft = pre.next will raise an error. As pre is None, the outer loop loses its benefit completely, and it becomes impossible to make the link
new = sll.head.data is always going to get the same data, in each iteration of the loop.
The name sll and new_sll are not the same, yet it seems the same is intended
Raising an error with description "error" is not going to help anyone.
Here is a correction:
def connect(self, sll):
if not isinstance(sll, SinglyLL):
raise TypeError("The connect method should be called with an SinglyLL instance as argument")
other = sll.head
if not other:
return
if self.head is None:
self.head = Node(other.data)
other = other.next
node = self.head
while node.next:
node = node.next
while other:
node.next = Node(other.data)
node = node.next
other = other.next
self.nodenumber += sll.nodenumber

Why creating an instance of a class within a class method changes the 'self' argument?

I'm writing a linked list in Python and I've come across an issue which is really troublesome and terrible for debugging and I feel like I'm missing something about Python. I'm supposed to create a singly linked list with some basic functionalities. One of them is the take() function, which is meant to create a new list of n first elements of the original list.
However, creating a new instance of the LinkedList class seems to change the .self parameter and the variable node is modified, as the attribute .next is turned to None. In result, when creating a list and then trying to make a new one out of the n elements of it, the program runs indefinitely, but no matter which part I look at, I cannot find the loop or the reason behind it.
class LinkedList:
def __init__(self, head=None):
self.head = head
def is_empty(self):
if self.head == None:
return True
else:
return False
def add_last(self, node):
if self.is_empty():
self.head = node
return
nextEl = self.head
while True:
if nextEl.next is None:
nextEl.next = node
return
nextEl = nextEl.next
def take(self, n):
node = self.head
newHead = self.head
newHead.next = None
newList = LinkedList(newHead)
count = 0
while count < n:
newList.add_last(node.next)
node = node.next
count += 1
return newList
class Node:
def __init__(self, data, next=None):
self.data = data
self.next = next
Thank you for all your help.
In the take() function the line
newHead.next = None
modifies a node of the linked list, breaking this list. You can fix this as follows:
def take(self, n):
node = self.head
newHead = Node(self.head.data)
newList = LinkedList(newHead)
count = 0
while count < n:
newList.add_last(node.next)
node = node.next
count += 1
return newList
This, however, still will not work correctly since there is a problem with the add_last() function too. This function, I think, is supposed to add a node as the last element of a linked list, but since you do not modify the next attribute of the node, you actually append a whole linked list starting with that node. This can be fixed in the following way:
def add_last(self, node):
if self.is_empty():
self.head = node
return
nextEl = self.head
while True:
if nextEl.next is None:
nextEl.next = Node(node.data)
return
nextEl = nextEl.next
There are more issues. For example, take(sefl, n) will actually create a list of n+1 elements and will throw an exception if it is applied to a linked list that does not have that many elements.

How does Python represent the LinkedList in terms of memory reference?

Note: I prefer to not use any external module since it is for interview prep purpose.
I know that there is no a built-in linked-list DS in python. However, we can implement the linked-list through a class Node. In the following code, I did a method (intersect_ll) to find an intersection between two linkedlists where the definition of intersections: node(s) are in the same order and value in the both linkedlists:
class Node:
def __init__(self, data=None, next=None):
self.data = data
self.next = next
class SingleLinkedList:
def __init__(self):
self.head = None
def add_node(self, data):
newNode = Node(data)
if self.head:
current = self.head
while current.next:
current = current.next
current.next = newNode
else:
self.head = newNode
def print_ll(self):
current = self.head
ll_data = []
while current:
ll_data += [current.data]
current = current.next
return ll_data
def intesect_ll (self, first_ll, second_ll):
current_first = first_ll.head
current_second = second_ll.head
if current_first is None or current_second is None:
return False
list_intersect = []
while current_first and current_second:
if current_first.data == current_second.data:
list_intersect += [current_first.data]
current_first = current_first.next
current_second = current_second.next
for item in list_intersect:
self.add_node(item)
return self.print_ll()
My Question is: :
I am pretty new to python so I am struggling to understand why comparing instead by memory reference is not working. In other word, why python did not give these two nodes with the same value and order in both linkedlists, the same memory location ?!. Is that because I am implementing my own data-structure and hence,I assume that python would take care of the rest which is not the reality?
if current_first is current_second
compiler result:
it gives two different memory references for the both nodes of the same value and order in both linkedlists. Hence, this does not work and need to make it (.data) comparing by value then.
I found out that what I expect from python to do in terms of memory management is not that what really happens. I need to allocate the same object and then reference it in both linked lists in order to comparing by reference becomes a valid solution.
assign ObjectA : locationA in memory
linkedlist1: node.next --> LocationA ---> n nodes
linkedlist2: node.next --> LocationA ----> k nodes
Otherwise, they are completely two different linkedlists and the interpreter would assign each one of the nodes into different memory location:
linkedlist1: node.next ---> locationX -- n nodes
linkedlist2: node.next ---> locationY --- k nodes
Hope that helps anyone would have the same concern

'AttributeError' in linked list in Python

This code deals with removal of duplicates from a linked list in Python. The problem seems to be in the remove function.
class Node(object):
def __init__(self, data = None, next_node = None):
self.next_node = next_node
self.data = data
#get data at that location
def get_data(self):
return self.data
#get next element in linked list
def get_next(self):
return self.next_node
#point to node specified by argument
def set_next(self, new_next):
self.next_node = new_next
class LinkedList(object):
def __init__(self, head = None):
self.head = head
#insert element in linked list
def insert(self, data):
new_node = Node(data)
new_node.set_next(self.head)
self.head = new_node
#remove duplicates
def remove(self):
#point to head
current = self.head
previous = None
removed = False
#variable to compare the current data with the rest
new = current
new = new.get_next()
#while current is not None
while current:
if current.get_data() != new.get_data():
previous = new
new = new.get_next()
#if same data, delete extra node from list
else:
removed = True
#if only one element in list
if previous is None:
self.head = new.get_next()
else:
previous.set_next(new.get_next())
new = new.get_next()
#if 'new' reaches end of list, do this
if new is None:
current = current.get_next()
previous = current
new = current
new = new.get_next()
if not removed:
print("No duplicates!")
#print resulting linked list
def print_result(self):
current = self.head
while current:
print(current.get_data(), end = " ")
current = current.get_next()
(I have ignored the 'function calling' part of the code).
I am getting an attribute error at the first if statement after while current: (in the remove function) saying:
Traceback (most recent call last):
File "python", line 64, in <module>
File "python", line 26, in remove
AttributeError: 'NoneType' object has no attribute 'get_data'
I can't understand which is None and why. Any help is greatly appreciated!
Your general approach appears correct, assuming you're OK with an exponential running time, but there are some details that will cause crashes. Here's a couple I spot offhand:
If the list is length 1, if current.get_data() != new.get_data(): will crash because new is None.
These lines:
current = current.get_next()
previous = current
new = current
new = new.get_next() # boom!
will crash when you reach the end of the list. current is the last node and you get the next, which is None, and then attempt to None.get_next().
To fix these, proceed through your list one node at a time and check for None every time you next to avoid crashing. Same goes for unlinking: only unlink one node at a time by keeping prev where it is and setting prev.next_node and curr to curr.next, then test if curr is None before doing anything else.
Here's a simple, working version:
def remove(self):
curr = self.head
while curr:
runner = curr.next_node
prev = curr
while runner:
if runner.data == curr.data:
prev.next_node = runner.next_node
else:
prev = runner
runner = runner.next_node
curr = curr.next_node
The idea is to use curr to step through the list node by node. For every node, create a runner and prev which will iterate through the remainder of the list node by node and unlink any nodes that match curr.
There's also a linear approach using a set (trading space for speed):
def remove_linear(self):
seen = set()
curr = self.head
prev = None
while curr:
if curr.data not in seen:
seen.add(curr.data)
prev = curr
else:
prev.next_node = curr.next_node
curr = curr.next_node
Try it!
A last note: Python generally doesn't use getters and setters; they add verbosity and don't offer any genuine protection, so I omitted them in my code above. Trust your client and use underscore prefixes for "private" variables.

Trouble with implementing a linked list in Python

There's this HackerRank problem about implementing a linked list. It is pretty basic and I thought I'd do it in a jiffy since I'd done all kinds of linked list implementations in C++. But I'm stuck somewhere.
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,
current = current.next
def insert(self,head,data):
new_node = Node(data)
if head == None:
head = new_node
else:
current = head
while current.next:
current = current.next
current.next = new_node
mylist= Solution()
T=int(input())
head=None
for i in range(T):
data=int(input())
head=mylist.insert(head,data)
mylist.display(head)
Only the insert function is editable. The rest of the code is provided by HackerRank and cannot be changed. The code doesn't print anything at the end of the insertions, and when I tried to print out the values while inserting, it seemed like the head kept on moving forwards instead of staying at the beginning.
You are appending the new_node after all the elements, and also you are not returning the newly created node. Modify your insert method like this:
def insert(self,head,data):
new_node = Node(data)
if head is not None:
current = head
new_node.next = current
return new_node
I think the error is here:
head = mylist.insert(head, data)
the method Solution.insert() is not returning anything, therefore head is assigned None every time.
When done, Solution.insert() must return the new_node created
The reason your code doesn't work is because of the None check that you are doing in insert method.
if head == None:
head = new_node
The head you are updating is local to the function insert and doesn't change head in the loop. So, head is always None in your loop.

Categories

Resources