Explanation about pointers vs manipulating objects in a linked list - python

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.

Related

Rearrange linked list in python

I am trying to solve the question on Cracking the Code Interview by using Python.
Question:
For example, suppose you had a linked list a1->a2->•••->an->b1->b2 ->••• ->bn and you wanted to
rearrange it into a1->b1 ->a2->b2-> •••->an->bn. You do not know the length of the linked list (but you
do know that a length is an even number).
But it turns out my code falls into an infinite loop after rearranging.
class Node(object):
def __init__(self, elem, next=None):
self.elem = elem
self.next = next
class SingleLinkList(object):
def __init__(self):
self.head = None
self.next = None
def is_empty(self):
return self.head == None
def append(self,item):
node = Node(item)
if self.is_empty():
self.head = node
node.next=None
else:
cur = self.head
while cur.next != None:
cur=cur.next
cur.next = node
node.next = None
def linked_list_rearrange(self):
fast = self.head
slow = self.head
while fast != None:
fast = fast.next.next
slow = slow.next
fast = self.head
while slow != None:
temp = slow.next
#print(temp.elem)
slow.next = fast.next
fast.next = slow
fast = slow.next
slow = temp
tlist=[0,1,2,3,4,5,6,7,8,9]
ll=SingleLinkList()
for i in tlist:
ll.append(i)
ll.linked_list_rearrange()
cur = ll.head
while cur!= None:
print(cur.elem,end=" ")
cur = cur.next
But when I forced to stop the loop by taking the first 10 nodes, it seems the data looks right.
while cur!= None:
print(cur.elem,end=" ")
if cur.elem == 9:
break
else:
cur = cur.next
Result:ResultN
I have no idea why my code is wrong. Could you please help me with that?
In your second while loop, when slow is on the last node, it is connected to fast and receives the next pointer of that fast node which still connects to the middle node of the list. This places a next link on slow which creates a circular reference in the list.
To avoid this, you could either change the condition of the second while (to check when fast reaches your initial slow) or break the next link of the node preceding your initial slow node before that second while loop.

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

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.

Merge Sort for linked list implementation in python is not working

Can someone please help me figure out what went wrong with this code? The code is printing the first node in the linked list instead of the sorted linked list.
class LinkedList(object):
def __init__(self):
self.head = None
class Node(object):
def __init__(self,data):
self.data = data
self.next = None
def push(self, new_data):
new_node = self.Node(new_data)
new_node.next = self.head
self.head = new_node
def print_list(self):
temp = self.head
while(temp):
print temp.data
temp = temp.next
merge two sorted lists
def merge_lists(head1, head2):
if(head1 is None):
return head2
if(head2 is None):
return head1
s = t= LinkedList.Node(None)
while(head1 and head2):
if(head1.data <= head2.data):
c= head1
head1 = head1.next
else:
c= head2
head2 = head2.next
t.next = c
t = t.next
t.next = head1 or head2
return s.next
split the linked list
def front_back_split(head):
if(head is None or head.next is None):
head1 = head
head2 = None
else:
slow = head
fast = head.next
while(fast != None):
fast = fast.next
if(fast!=None):
slow = slow.next
fast = fast.next
head1 = head
head2 = slow.next
slow.next = None
return head1, head2
merge sort
def merge_sort(head):
if(head is None or head.next is None):
return
a,b = front_back_split(head)
merge_sort(a)
merge_sort(b)
new_head = merge_lists(a,b)
return new_head
main
if __name__=='__main__':
llist1 = LinkedList()
llist1.push(6)
llist1.push(7)
llist1.push(1)
llist1.push(4)
llist1.push(3)
llist1.push(8)
print "Sorted list"
new_head = merge_sort(llist1.head)
llist1.print_list()
This response applies to an earlier version of the code. See my new response for fixes for the new version of the code.
Ok, it looks like the problem is the way you're returning linked lists from functions. In front_to_back_split, you're assigning to head1 and head2, but those are just parameters to the function. I.e., they're local variables. Assigning to them has no effect on the caller.
A better way to do it is to eliminate head1 and head2 as arguments, and instead just make them ordinary local variables. Then change it to return head1 and head2, like so:
return head1, head2
Then, in merge_sort, you no longer need to allocate a and b. Instead, you can just do:
a, b = front_to_back_split(head)
Similarly, merge_sort should return the new head so the caller can use it. Otherwise the caller has no way to determine what the new list head is.
Ok, I've debugged your updated version and it now works. There are three changes:
At the top of merge_sort there's a bare return. Change it to:
return head
In merge_sort, change the recursive calls so that they update a and b, as follows:
a = merge_sort(a)
b = merge_sort(b)
In your main code, after sorting the list, you need a LinkedList with the new head in order to print it, since llist1 will still point to the old head. You can use this:
print "Sorted list"
new_head = merge_sort(llist1.head)
new_list = LinkedList()
new_list.head = new_head
new_list.print_list()

Python Reverse a Linked List

I am doing a Python program that implements linked list to support a few functions, one of the functions I need to do is to reverse a stack. I have made a Node, LinkedList and Stack classes, here is my Code so far:
class ListNode:
def __init__(self, Object):
self.Object = Object
self.next = None
class LinkedList:
def __init__(self):
self.head = None # first node
self.tail = None # last node
def addLast(self, Object):
newNode = ListNode(Object)
if self.head == None:
self.head = newNode
self.tail = newNode
else:
self.tail.next = newNode
self.tail = newNode
def removeFirst(self):
if self.head == None:
return
self.head = self.head.next
if self.head == None:
self.tail = None
def removeLast(self, Object):
if self.head == None:
return
current = self.head
prev = None
while current.next != None:
prev = current
current = current.next
if prev == None:
self.head = None
self.tail = None
else:
prev.next = None
self.tail = prev
def get(self, index):
current = self.head
i = 0
while i < index and current != None:
current = current.next
i = i + 1
if current != None and index >= 0:
return current.Object
else:
return None
def size(self):
current = self.head
count = 0
while current != None:
count = count + 1
current = current.next
return count
def isEmpty(self):
return self.head == None
def printList(self):
if self.head != None:
current = self.head
while current != None:
print(current.Object, end = ' ')
current = current.next
print()
# -------------------- STACK ---------------------------------------------------
class Stack:
# constructor implementation
def __init__(self):
self.llist = LinkedList()
def front(self):
return self.llist.get(0)
def dequeue(self):
self.llist.removeFirst()
def queue(self, Object):
self.llist(Object)
def push(self, Object):
self.llist.addLast(Object)
def pop(self, Object):
self.llist.removeLast(Object)
def printStack(self):
self.llist.printList()
def size(self):
return self.llist.size()
def isEmpty(self):
return self.llist.isEmpty()
# ----------------------- Reverse LIST ------------------------------
def Reverse(S):
# S is a Stack Object
Here is my attempt at the problem:
def rRecursive( self ) :
self._rRecursive( self.head )
def _reverseRecursive( self, n ) :
if None != n:
right = n.next
if self.head != n:
n.next = self.head
self.head = n
else:
n.next = None
self._rRecursive( right )
def Reverse(S):
s.rRecursive()
If this was an ordinary list I could easily reverse it using [::-1] but I cannot since the linkedlist is an object. I was thinking maybe I could use temporary values so I can someone append the beginning of the stack to a list and then somehow convert it back into a stack object.
Edit for duplication: The goal of my program is use an existing Stack and reverse it. The linked post deals with a linked list that was already in a list format.
def get(self, index):
current = self.head
i = 0
while i < index and current != None:
current = current.next
i = i + 1
if current != None and index >= 0:
return current.Object
else:
return None
Edit 2: added my get function.
class Stack:
# constructor implementation
def __init__(self):
self.llist = LinkedList()
def front(self):
return self.llist.get(0)
# push method implementation
def push(self, Object):
self.llist.addLast(Object)
def pop1(self):
self.llist.removeLast1()
def Reverse(S):
new_stack = Stack()
while not S.isEmpty():
new_stack.push(S.front())
S.pop1()
return new_stack
# Current Stack after Push: 12 14 40 13
# Stack after Pop: 12 14 40
# Stack after Reversal: 12 12 12
Edit 3: Added a rework of my code, it returns back a wrong reversal with the first element over and over again.
It's quite easy to reverse a stack using basic stack operations. Pop each item off the old stack and push it onto a new one.
def reverse(stack):
new_stack = Stack()
while not stack.isEmpty():
new_stack.push(stack.front())
stack.pop()
return new_stack
You could do something similar to destructively reverse the LinkedList within the Stack while reusing the stack object itself, you'd just need to use the list operations rather than the stack operations that are aliased to them.
Speaking of stack operations, you'll probably find that your stack performs better if you push and pop from the front, rather than the back. Removing an item from the end of the linked list requires iterating over the whole list (to find the next-to-last node). In contrast, both adding and removing from the front are fast.
You shouldn't have to fiddle with link pointers in your reversal function. I assume that you have a pop() method and other basics with your stack; if not, then clone your removeFirst function to return the removed node.
Now, the recursive function is simple: pop the head of the list, reverse the remaining stack (if any), and add the popped node to the end. Does this handle your problem?
def reverseStack(self):
move_me = self.pop()
if not self.isEmpty():
return (self.reverseStack()).addLast(move_me)
else:
new_stack = Stack()
return new_stack.addLast(move_me)
Other approaches to solving this problem: Cheat.
Define a __iter__ method (which makes sense in any event; iteration is a core Python behavior) to make your type iterable. Simple example:
def __iter__(self):
cur = self.head
while cur is not None:
yield cur.Object
cur = cur.next
Then just do:
values = list(self) # Creates a list containing the current set of values
self.head = self.tail = None # Clear existing linked list
# Add back all the values in reverse order
for value in reversed(values):
self.addLast(value)
Sure, it's likely less efficient in memory allocation/deallocation overhead than doing it properly. But the effect is likely marginal, and it simplifies the implementation code dramatically.
Of course, doing it properly isn't that hard, it's just slightly more confusing (totally untested, but it should be close to right):
def reverse(self):
# Start at beginning, which will be new end
cur, last = self.head, None
# Reverse head and tail pointers in advance
self.head, self.tail = self.tail, self.head
# Traverse while reversing direction of each node pointer
while cur is not None:
# Tuple pack and unpack allows one-line variable swap
cur.next, cur, last = last, cur.next, cur
The usual algorithm for reversing things using basic data structures is to use the fact that a stack is a first in last out data structure. That means if you pop until the stack is empty, you will get the items in the opposite order you pushed them on.
But it looks like you want to do this via recursive functions rather than an explicit stack - in this case, your function would normally fetch the front element,then recurse on the rest of the data structure, then handle that first element. This gets all the elements off in order, but handles them in the opposite order as each recursive call finishes and you work your way back up the call stack. If you neex to add the elements to a reversed data structure (and not just print them), you can build it up via return values by noticing that once you have the reverse if everything after the current element, you just need to attach that element to the front and you have the reverse of everything you were handed.
class Node(object):
def __init__(self, data=None, next_node=None):
self.data = data
self.next = next_node
def Reverse(head):
if head == None :
return None
elif head.next == None :
return head # returns last element from stack
else :
temp = head.next # stores next element while moving forward
head.next = None # removes the forward link
li = Reverse(temp) # returns the last element
temp.next = head # now do the reverse link here
return li
def main() :
temp4 = Node(4,None)
temp3 = Node(3,temp4)
temp2 = Node(2,temp3)
head = Node(1,temp2)
res = Reverse(head)
while res != None :
print(res.data)
res = res.next
main()

Categories

Resources