Rearrange linked list in python - 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.

Related

How to connect single linked list

I wanted to solve the palindrome linked list problem.
I went through the linked list, but I don't know how to refer to it in a different function. Here's my code (not working):
def __init__ (self):
self.head = None
def add_end(self, data):
newNode = Node(data)
n = self.head
if self.head is None:
self.head= newNode
n = self.head
while n:
n = n.ref
return self.head
def palindrom(self):
fast = self.head
slow = self.head
while fast and fast.ref:
fast = fast.next.ref
slow = slow.ref
#reserve second half
prev = None
while slow:
tmp = slow.ref
slow.ref = prev
prev =slow
slow = tmp
Could you please help me solve the problem?

Sort linked list by using Quick sort in python

I'm new to python. I have the following list of books stored on the linked list and I want to sort them by using quicksort but unfortunately, I'm stuck on a problem.
class Node:
def __init__(self, data=None):
self.data = data
self.prev = None
self.next = None
class DoublyLinkedList:
def __init__(self):
self.head = None
self.tail = None
def append_value(self, x):
if not isinstance(x, Node):
x = Node(x)
if self.is_empty():
self.head = x
else:
current = self.head
while current.next:
current = current.next
current.next = x
x.prev = current
self.tail = x
def length(self):
count = 0
current = self.head
while current:
count += 1
current = current.next
return count
def is_empty(self):
return self.head is None
def __str__(self):
to_print = ''
current = self.head
while current:
to_print += f'{current.data} <-> '
current = current.next
if to_print:
return f'[{to_print[:-5]}]'
return '[]'
def quick_sort(self, arr):
if self.length() < 2:
return self
else:
pivot = self.tail.data
smaller, equal, larger = [], [], []
current = self.head
while current:
if current.data < pivot:
smaller.append(current.data)
elif current.data == pivot:
equal.append(current.data)
else:
larger.append(current.data)
current = current.next
return self.quick_sort(smaller) + equal + self.quick_sort(larger)
This is the quicksort method but it's giving me RecursionError on 'return self.quick_sort(smaller) + equal + self.quick_sort(larger)'. How do I sort the linked list by using quicksort?
my_list = DoublyLinkedList()
my_list.append_value('In Search of Lost Time')
my_list.append_value('Ulysses by James Joyce')
my_list.append_value('Within a Budding Grove')
my_list.append_value('The Guermantes Way')
my_list.append_value('In Search of Lost Time')
my_list.append_value('Sodom & Gomorrah')
my_list.append_value('One Hundred Years of Solitude')
my_list.append_value('War and Peace')
print(f'List of Books: {my_list}')
print(f'Quick Sort: {my_list.quick_sort(my_list)}')
Indeed, the error occurs because you pass a standard list to quick_sort, while it expects the argument to be a doubly linked list instance.
Moreover, it would be strange if the use of lists were allowed in this algorithm, as then one may wonder why there is a doubly linked list in the first place. If you're going to use lists, then you might as well store the data in a list and sort the list. This cannot be the purpose.
Some other comments about the code:
quick_sort is a method of the class, so it should not be necessary to pass the linked list also as argument. Instead, pass two arguments that identify the start and end node of a subsection in that linked list.
The final return statement is problematic. If indeed quick_sort is going to return a linked list, then + is not an operator you can use on those. Moreover, Quick Sort is supposed to be an in-place sorting algorithm, while + suggests a new list being created. As it is in-place, you should be able to just return self.
So, ... you really need to solve this by walking through the linked list and manipulate it.
Here is one way to do it. First define two methods that allow inserting and deleting a node anywhere in the list:
def remove_node(self, node):
if node.prev:
node.prev.next = node.next
else:
self.head = node.next
if node.next:
node.next.prev = node.prev
else:
self.tail = node.prev
node.next = node.prev = None
return node
def insert_after(self, prev, node):
if not isinstance(node, Node):
node = Node(node)
node.prev = prev
if prev:
node.next = prev.next
prev.next = node
else:
node.next = self.head
self.head = node
if node.next:
node.next.prev = node
else:
self.tail = node
return self
The latter is in fact a more flexible method than the append_value you already had. You could actually make use of this new one to define yours:
def append_value(self, x):
return self.insert_after(self.tail, x)
Then perform the quick sort as follows:
Take a start and end node as arguments. Extract (remove) the end node from the list and consider it the pivot. Let two references walk along this sublist towards each other, starting at the ends. When their values are at the good side of the pivot value, let that reference move closer. Once you have two references where the value is opposite from the pivot, swap the data that is in these two nodes. Once these two references cross each other you have identified the two partitions. Inject the pivot node back into the list, right between those two partitions. Finally, use recursion to do the same with the two partitions:
def quick_sort(self, start=None, end=None):
if not start and not end: # set default arguments:
start = self.head
end = self.tail
if not start or not end or start == end or end.next == start:
# The sublist is empty or has just one value
return self
# Extract the pivot node from the list
end, pivot = end.prev, self.remove_node(end)
pivotdata = pivot.data
# Define two references that will walk towards eachother:
right = end
left = start
while left and left.prev != right: # While they didn't cross over
if left.data <= pivotdata:
left = left.next
elif right.data >= pivotdata:
right = right.prev
else: # Swap values, not the nodes:
left.data, right.data = right.data, left.data
left = left.next
right = right.prev
# Insert the pivot node between the two partitions
self.insert_after(right, pivot)
# Sort the non-empty partitions recursively
if start.prev != pivot:
self.quick_sort(start, right)
if end.next != pivot:
self.quick_sort(left, end)
return self

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 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()

Sort a linked list in O(n log n) time using merge sort

This is actually a algorithm practice of Leetcode. and below is my code:
class ListNode:
def __init__(self, x, next=None):
self.val = x
self.next = next
class Solution:
# #param head, a ListNode
# #return a ListNode
def sortList(self, head):
if head is None or head.next is None:
return head
first, second = self.divide_list(head)
self.sortList(first)
self.sortList(second)
return self.merge_sort(first, second)
def merge_sort(self, first, second):
if first is None:
return second
if second is None:
return first
left, right = first, second
if left.val <= right.val:
current, head = left, first
left = left.next
else:
current, head = right, second
right = right.next
while left and right:
if left.val <= right.val:
current.next = left
left = left.next
else:
current.next = right
right = right.next
current = current.next
if left is not None:
current.next = left
if right is not None:
current.next = right
return head
def divide_list(self, head):
fast, slow = head.next, head
while fast.next:
slow = slow.next
fast = fast.next
if fast.next:
fast = fast.next
second_part = slow.next
slow.next = None
return head, second_part
the idea is quite straightforward, just the basic concept of Merge Sort. but the result seems incorrect and the running time is cost too much that can't pass the judgement of Leetcode(Time Limit Exceeded, BUT why not O(nlog(n))?). and below is my test code:
Basic test:
c= ListNode(3, ListNode(1, ListNode(2, ListNode(4))))
result =Solution().sortList(c)
while result:
print result.val
result = result.next # result: 2, 3, 4 which missing 1
anyone have idea to optimize this code?
The offending lines are
self.sortList(first)
self.sortList(second)
The problem is that the list head may change after sorting. The fix is
first = self.sortList(first)
second = self.sortList(second)
As a general hint, I would suggest that you employ sentinel nodes to cut down on the number of special cases.

Categories

Resources