Trouble with implementing a linked list in Python - 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.

Related

How does print_list() Iterate though a Linked List in python?

The code works and outputs 1,5, and 6.
After print_list(), prints the first value ( 1 ), how does temp = temp.next result in temp.value being 5 on the next pass.
I am missing something but I've been at this for days. I just don't understand how temp.next is pointing at 5 or the next node.
I also understand that temp, head, and tail are pointers. Please help, I am trying to learn what every line of code is doing.
class Node:
def __init__(self, value):
self.value = value
self.next = None
class LinkedList:
def __init__ (self, value):
new_node = Node(value)
self.head = new_node
self.tail = new_node
self.lenth = 1
def print_list(self):
temp = self.head
while temp is not None:
print(temp.value)
temp = temp.next
def append(self, value):
new_node = Node(value)
if self.head is None:
self.head = new_node
self.tail = new_node
else:
self.tail.next = new_node
self.tail = new_node
self.lenth =+ 1
return True
my_linked_list = LinkedList(1)
my_linked_list.append(5)
my_linked_list.append(6)
my_linked_list.print_list()
When thinking about a linked list data structure, you can conceptualize the structure as a list of boxes chained together, with the first box connected to the next, that one connected to the next, and so on, until you reach the last box and there's nothing it's chained to. Here's a rough visual demonstration:
[5] -> [7] -> [9] -> [3] -> None
This linking between boxes is denoted by having the first node of the linked list (a.k.a the head), have a reference to the next box in the list. In your code example this reference is stored in the next attribute. And this next node has a reference stored in it, which points to the next, next node. And this process continues on, creating the chain-like behavior I mentioned above.
What print_list is doing is starting at the head of the linked list, printing the head's data, and then using the reference the head has to the next box in the linked list to get that next box, print it's data, and then use this next boxes reference to get the next box in the list. This process continues on until the last box is reached, which has no further reference, so the code terminates (this is what the while temp is not None: condition checks for).
I commented each line below to connect what I said a bit more concretely to the actual code:
def print_list(self):
# Set temp to be equal to the first box in the list
temp = self.head
# temp will be set to none when we try to set it to be equal to
# the next box the last box in the list is pointing to. So we
# know we've reached the end of the list when temp is none,
# meaning we should break out of the loop and finish.
while temp is not None:
# Print the data in the current box, starting with head...
print(temp.value)
# And then get the next box in the list so we can print it's data.
temp = temp.next

Explanation about pointers vs manipulating objects in a linked list

I am having trouble wrapping my head around the concept of switching pointers vs actual manipulation of objects in a linked list.
Here is the code for building the linked list from scratch
class ListNode:
def __init__(self, val:int, nextNode=None):
self.val = val
self.next = nextNode
class LinkedList:
def __init__(self, val=None):
self.head = None
self.tail = None
def addValue(self, val:int):
if self.head == None:
self.head = self.tail = ListNode(val)
else:
self.tail.next = ListNode(val)
self.tail = self.tail.next
return self.tail
def addMultiple(self, values:list):
for i in values:
self.addValue(i)
def add_to_beginning(self, val):
if self.head == None:
self.head = self.tail = ListNode(val)
else:
self.head = ListNode(val, self.head)
def display(self):
elems = []
curr = self.head
while curr:
elems.append(curr.val)
curr = curr.next
print(elems)
creating a linked list here:
l1 = LinkedList()
l1.addMultiple([1,2,3,4,5])
For example if I wanted to move the nth element to the head, so I created this function
class Solution:
def move_n_to_head(self, head, n):
if head == None:
return None
if head.next == None:
return head
temp = None
count = 0
dummy = fast = slow = ListNode(0)
fast.next = head
while fast:
if count == n:
temp = fast.next
fast.next = fast.next.next #why does this line manipuate the head?
break
fast = fast.next #why does this line NOT manipulate the head?
count += 1
slow.next = temp
slow.next.next = head
return dummy.next
Everything works fine and I got the solution I wanted, but specifically I don't understand why this line does manipulate the head?
fast.next = fast.next.next
After using this above line in the 3rd iteration, the head now becomes [1,2,3,5]
However while this line does not manipulates the head as I am traversing through the list? The head remains [1,2,3,4,5] after every iteration?
fast = fast.next
I read this other stackoverflow explanation on dummy node pointers which was helpful but I still don't understand it.
Explanation about dummy nodes and pointers in linked lists
Thanks in advance!
First of all, it is good to see such a clear and easy to read code. Now, the reason why the following line doesn't work
fast.next = head #fast is an object.
is because you are declaring fast as an object
dummy = fast = slow = ListNode(0) #just here
What happens?
In python you are working with objects rather than pointers (and pointers really aren't that, they are references.
Sometimes some variables passed or created are interpreted as objects and sometimes as pointers (references).
Well, you will see:
Python doesn't need pointers in order to achieve this as every variable is a reference to an object. These references are slightly different from C++ references, in that they can be assigned to - much like pointers in C++. (obmarg)
It is quite hard to tell you how to make the lenaguage interpret variables as object references.
If I think about it well, it may be done in this case with the following modification
class Solution:
def move_n_to_head(self, head, n):
if head == None:
return None
if head.next == None:
return head
temp = None
count = 0
dummy = slow = ListNode(0)
fast = head #fast now "points" to head
# (it depends if it is taken as a copy of head or a reference to it)
while fast:
if count == n:
temp = fast.next
fast.next = fast.next.next #It should be solved
break
fast = fast.next
count += 1
slow.next = temp
slow.next.next = head
return dummy.next
Note:
This post discusses how to implement pointers in python, and may give you more information about how to handle them.
I really hope it helps you, thanks for reading this answer.

Python Linked List Implementation and Object Modeling

I am trying to implement Single Linked List on Python and the Code below works fine but I can not understand how:
class Node(object):
def __init__(self, data=None, ):
self.value = data
self.next = None
class LinkedList1(object):
def __init__(self, data=None):
self.head = Node(data)
self.tail = self.head
self.length = 1
def append(self, data):
self.tail.next = Node(data)
self.tail = self.tail.next
self.length += 1
return self
def show_list(self):
head_copy = self.head
while head_copy is not None:
print(head_copy.value)
head_copy = head_copy.next
When we test it:
linkin = LinkedList1(10)
linkin.append(20)
linkin.append(30)
linkin.append(40)
linkin.show_list()
output :
10
20
30
40
What I don't understand is append function. I know self.tail referencing self.head but how come sefl.tail.next adds the new Node(data) to the at the last next, in my logic without a loop it should add to first next.
Plus if we write the function this way:
def append(self, data):
self.head.next = Node(data)
self.tail = self.head.next
self.length += 1
return self
This doesn't work even if self.tail reference to self.head.
I know I am missing something here. Can you help me understand?
Thank you.
If you refer to the class Node, it has two objects: value and next Node.
In the Linked list implementation, it is implemented in such a way that the tail Node information is stored as well. In the append function, self.tail.next = Node(data) basically adds a new node after the tail node and self.tail = self.tail.next reassigns the Linked list's tail node to the newly created Node (which is now the last node of the list)
For example, let's take the following code:
linkin = LinkedList1(10)
linkin.append(20)
linkin.append(30)
linkin.append(40)
linkin.show_list()
A Linked list is created with self.head -> Node(10) and self.tail -> Node(10)
Appending 20 changes the list: self.head -> Node(10), self.tail.next -> Node(20) [which is same as self.head.next] 10 -> 20 where 10 is head and 20 is tail
Appending 30 changes the list: self.tail.next -> Node(30) [self.tail here is Node(20)] and Node(30) is now made as tail 10 -> 20 -> 30 where 10 is head and 30 is tail
Hope this helps.
self.tail is only set to self.head when there is a single node. tail is always changed to point to the LAST node, which is the same as the head node only before the second node is added.
Every time append is called, tail is changed to point to the node that was just added.
It doesn't make much sense to append to the first node, does it? That would get rid of the rest of the list.
Let's take it line by line:
def append(self, data):
self.tail.next = Node(data)
Before this is executed, self.tail.next is None, which indicates the list ends there. Now that we've set it to a new Node, that new node has a "next" value that is None.
self.tail = self.tail.next
Since self.tail needs to point to the LAST item in the list, we need to change it. So, the above line changes it to point to the NEW last item.
self.length += 1
return self
These just keep track of length and return. As long as it is done correctly, you won't need to run through the list just to know how many nodes are in it.

Linked list not working properly?

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

What is sytanx for -> in linked list python

Hey everyone I am trying to print (2->None, 3) in the linked list below, but am getting a syntax error. can someone please help me with this syntax cannot find on google for some reason. Code below:
class Node(object):
def __init__(self, data=None, next_node=None):
self.data = data
self.next = next_node
def Insert(head, data):
if head == None:
head = Node(data)
print(head)
else:
current = head
while current.next != None:
current = current.next
current.next = Node(data)
return head
print Insert(2->None, 3) # -> is bringing a syntax error, how do I write this in python 2.7?
Honestly, I think your confused about how to implement a linked list in the first place. If you want a linked list in the form of:
[2] -> [3] -> [None]
Then you need to insert each element backwards. First None then 3 then 2. You also need to make your insert method inside of a class because you need to save state. Here is what I'd recommend instead:
class Node(object):
def __init__(self, data, next_node=None):
self.data = data
self.next_node = next_node
# Create a class not a function because we need to save state
# More specficly, we need to create a "global" variable which
# keeps track of the head of the linked list.
class LinkedList(object):
def __init__(self):
self.head = None
# Put the insert function inside of of the class.
# That way, we can save and load the state of self.head.
def insert(self, data):
new_node = Node(data, self.head)
self.head = new_node
# demo
ll = LinkedList()
# insert the elements in the reverse order you want
# them to appear.
ll.insert(None)
ll.insert(3)
ll.insert(2)
print("Head:", ll.head.data) # Head: 2
print("Middle:", ll.head.next_node.data) # Middle: 3
print("Tail:", ll.head.next_node.next_node.data) # Tail: None
Also, I recommend to a little research as well. Such as this article. Or just google Linked List in Python and browse over some of the results.
I have a feeling you just want to insert None as the first argument as what #leaf said. In that case, just directly use None:
print Insert(None, 3)
-> doesn't exist in Python as of now. This is #leaf's comment:
If you want to pass in none, simply pass in None: Insert(None, 3). Python doesn't have pointer in the sense your thinking about.

Categories

Resources