We were tasked to do the following code.
You are given a linked list that contains N integers. You are to perform the following reverse operation on the list:
Select all the subparts of the list that contain only even integers. For example, if the list is {1,2,8,9,12,16}, then the selected subparts will be {2,8}, {12,16}.
Reverse the selected subpart such as {8,2} and {16,12}.
The list should now be {1,8,2,9,16,12}.
The problem is that it is not creating the sublist and give me output like [2, 8, 12, 16], but I want it like {2,8}, {12,16}.
Below is my code:
class Node:
def __init__(self, data=None):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
self.tail = None
def append_value(self, x):
if not isinstance(x, Node):
x = Node(x)
if self.head is None:
self.head = x
else:
self.tail.next = x
self.tail = x
def reverse_list_recursive(self, current, previous):
if self.head is None:
return
elif current.next is None:
self.tail = self.head
current.next = previous
self.head = current
else:
next = current.next
current.next = previous
self.reverse_list_recursive(next, current)
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[:-2]}]'
return '[]'
This is my function:
def reverse_sub_parts(self):
sublist_list = list()
current = self.head
while current:
if current.data % 2 == 0:
sublist_list.append(current.data)
current = current.next
print(sublist_list)
my_list = LinkedList()
my_list.append_value(1)
my_list.append_value(2)
my_list.append_value(8)
my_list.append_value(9)
my_list.append_value(12)
my_list.append_value(16)
my_list.reverse_sub_parts()
The loop is explicitly adding all nodes that have even numbers to a single list (sublist_list). The statement sublist_list = list() is only executed once, so there is no way you could ever hope to get more than one list like that.
Secondly, even if you manage to create a variable number of lists like that, you would still need to have logic to reverse those new lists (trivial), and to replace the original sublists inside the original list with the reversed lists (less trivial).
In the end, it is not making things easier like this.
I would suggest to first make your reverse_list_recursive function more versatile, so it can also do the job for a subsection of the list, by letting it accept two more arguments: the node the precedes that section, and the node the follows it. Both would be None by default, which means that the whole list should be reversed.
I would also suggest to not use a recursive solution, as this will use stack space that is linear with the number of nodes in the list, and so if the list would have like thousands of nodes, you will run into a stack size limit.
So here is an iterative reverse function, that takes these extra, optional arguments:
def reverse(self, before_first=None, after_last=None):
prev = after_last
current = before_first.next if before_first else self.head
while current and current != after_last:
prev, current.next, current = current, prev, current.next
if before_first:
before_first.next = prev
else:
self.head = prev
Now the hardest part has been done really, as you now only need to identify the nodes that bound the sequences of even-numbered nodes:
def reverse_sub_parts(self):
prev = None
current = self.head
while current:
if current.data % 2 == 0:
if not prev or prev.data % 2 == 1:
before_start = prev
elif prev and prev.data % 2 == 0:
self.reverse(before_start, current)
prev = current
current = current.next
if prev and prev.data % 2 == 0:
self.reverse(before_start)
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
I'm working on a problem that accepts a linked list as input, at this point I don't even know how to set up an example linked list.
My initial problem is understanding the following instruction:
Write a function that accepts a linked list as input, then reverses that linked list.
Does this simply involve defining a 'reversing summary' as part of the following or is there some other way of summarizing a linked lists in Python:
class Node(object):
# Initialize with a single datum and pointer set to None
def __init__(self, data=None, next_node=None):
self.data = data
self.next_node = next_node
# Returns the stored data
def get_data(self):
return self.data
# Returns the next node
def get_next(self):
return self.next_node
# Reset the pointer to a new node
def set_next(self, new_next):
self.next_node = new_next
def set_data(self, data):
self.data = data
class LinkedList(object):
# Top node in the list created on __init__
def __init__(self, head=None):
self.head = head
# Take in the new node and point the new node to the prior head O(1)
def insert(self, data):
new_node = Node(data)
new_node.set_next(self.head)
self.head = new_node
# Counts nodes O(n)
def size(self):
current = self.head
count = 0
while current:
count += 1
current = current.get_next()
return count
# Checks each node for requested data O(n)
def search(self, data):
current = self.head
found = False
while current and found is False:
if current.get_data() == data:
found = True
else:
current = current.get_next()
if current is None:
raise ValueError("Data not in list")
return current
# Similar to search, leapfrogs to delete, resetting previous node pointer to point to the next node in line O(n)
def delete(self, data):
current = self.head
previous = None
found = False
while current and found is False:
if current.get_data() == data:
found = True
else:
previous = current
current = current.get_next()
if current is None:
raise ValueError("Data not in list")
if previous is None:
self.head = current.get_next()
else:
previous.set_next(current.get_next())
It seems all of the code you have for your base Linked List class is there. You just need to reverse your Linked List. Reversing a linked list is like follows.
[1] -> [2] -> [3] -> NULL
You can tell that 1 is the Head and 3 is the Tail (meaning that it's the last node that is in the linked list because it points to NULL or None in Python). What you need to do is figure out some algorithm that will take that linked list and produce this result.
[3] -> [2] -> [1] -> NULL
Now 3 is the Head and 1 is the Tail.
So using Psuedocode:
Initalize 3 Nodes: prev, next, and current
current = head
prev = None
next = None
While current != None
next = current.next
current.next = prev
prev = current
current = next
head = prev
I'm new to python and have been trying to learn simple data structures. I've been able to hack together some functions for a linked list and have been having trouble with my delete function. Heres list with the function in question and the test case:
class Node:
def init(self, initial_data):
self.data = initial_data
self.next = None
def get_data(self):
return self.data
def get_next(self):
return self.next
def set_data(self, new_data):
self.data = new_data
def set_next(self, new_next):
self.next = new_next
class LinkedList:
def init(self):
self.head = None
def __str__(self):
output_string = ''
current = self.head
while current is not None:
output_string += str(current.get_data())
next_node = current.get_next()
#gives the pointer to the next node i.e. the next node is that which is next to the current
if next_node is not None:
output_string += "->"
current = next_node
return output_string
#does not need to be changed for ordered linked list
def is_empty(self):
if self.head is None:
return True
else:
return False
def insert(self, data):
current = self.head
previous = None
stop = False
while current != None and not stop:
if current.get_data() > data:
stop = True
else:
previous = current
current = current.get_next()
temp = Node(data)
if previous == None:
temp.set_next(self.head)
self.head = temp
else:
temp.set_next(current)
previous.set_next(temp)
#does not need to be changed for ordered linked list
def size(self):
current = self.head
count = 0
while current != None:
count += 1
current = current.get_next()
return count
def search(self, item):
current = self.head
found = False
stop = False
while current is not None and not found and not stop:
if current.get_data() == item:
found = True
else:
current = current.get_next()
return found
def delete(self, item):
current = self.head
previous = None
found = False
while not found:
if current.get_data() == item:
found = True
else:
previous = current
current = current.get_next()
if previous is None:
self.head = current.get_next()
else:
previous.set_next(current.get_next())
def test_nonexistent():
my_list = LinkedList()
my_list.insert(31)
my_list.insert(77)
my_list.insert(17)
my_list.insert(93)
my_list.insert(26)
my_list.insert(54)
assert my_list.size() == 6
my_list.delete(77)
my_list.delete(1)
assert my_list.size() == 5
I get the error message
"AttributeError: 'NoneType' object has no attribute 'get_data' with
delete Function"
I believe there is something wrong with the delete function as it can't handle a value thats isn't in the list, but I'm stumped as to how to get it to work at this point. Any help is appreciated!
You are using None to indicate there are no further nodes in the list, i.e. that you're at the end, but you never test for that when you're searching the list, so when you reach the end you try to call None.get_data(). Solution: don't do that.
A good way to rework the loop might be to change the while loop to test current and use break to exit the loop when the item is found.
while current is not None:
if current.get_data() == item:
break
else:
previous = current
current = current.get_next()
You'll need to redo some of the later logic to account for this. You don't need the separate found flag; you can simply check current. If it's None, you reached the end of the list without finding the item you were looking for. Otherwise, you found it, and current is it.
It's a bit hard to figure this out as you haven't posted the actual LinkedList but I assume that you are calling current.get_next() too many times and you probably reach the end of the list. Maybe something like this does the magic for you (UPDATE):
def delete(self, item):
current = self.head # we don't need the previous variable
previous = None
found = False
while current is not None and not found:
if current.get_data() == item:
found = True
else:
previous = current
current = current.get_next()
# at this point we should have either reached to end of the list
# and current is None
# or we have found the node we were looking for
if found and previous is not None:
# delete it
previous.set_next(current.get_next())
elif found and previous is None:
# removing head element
self.head = None
else:
# nothing found
print("Do whatever you want here")
I am asked to reverse a which takes head as parameter where as head is a linked list e.g.: 1 -> 2 -> 3 which was returned from a function already defined I tried to implement the function reverse_linked_list in this way:
def reverse_linked_list(head):
temp = head
head = None
temp1 = temp.next
temp2 = temp1.next
temp1.next = None
temp2.next = temp1
temp1.next = temp
return temp2
class Node(object):
def __init__(self,value=None):
self.value = value
self.next = None
def to_linked_list(plist):
head = None
prev = None
for element in plist:
node = Node(element)
if not head:
head = node
else:
prev.next = node
prev = node
return head
def from_linked_list(head):
result = []
counter = 0
while head and counter < 100: # tests don't use more than 100 nodes, so bail if you loop 100 times.
result.append(head.value)
head = head.next
counter += 1
return result
def check_reversal(input):
head = to_linked_list(input)
result = reverse_linked_list(head)
assert list(reversed(input)) == from_linked_list(result)
It is called in this way: check_reversal([1,2,3]). The function I have written for reversing the list is giving [3,2,1,2,1,2,1,2,1] and works only for a list of length 3. How can I generalize it for a list of length n?
The accepted answer doesn't make any sense to me, since it refers to a bunch of stuff that doesn't seem to exist (number, node, len as a number rather than a function). Since the homework assignment this was for is probably long past, I'll post what I think is the most effective code.
This is for doing a destructive reversal, where you modify the existing list nodes:
def reverse_list(head):
new_head = None
while head:
head.next, head, new_head = new_head, head.next, head # look Ma, no temp vars!
return new_head
A less fancy implementation of the function would use one temporary variable and several assignment statements, which may be a bit easier to understand:
def reverse_list(head):
new_head = None # this is where we build the reversed list (reusing the existing nodes)
while head:
temp = head # temp is a reference to a node we're moving from one list to the other
head = temp.next # the first two assignments pop the node off the front of the list
temp.next = new_head # the next two make it the new head of the reversed list
new_head = temp
return new_head
An alternative design would be to create an entirely new list without changing the old one. This would be more appropriate if you want to treat the list nodes as immutable objects:
class Node(object):
def __init__(self, value, next=None): # if we're considering Nodes to be immutable
self.value = value # we need to set all their attributes up
self.next = next # front, since we can't change them later
def reverse_list_nondestructive(head):
new_head = None
while head:
new_head = Node(head.value, new_head)
head = head.next
return new_head
I found blckknght's answer useful and it's certainly correct, but I struggled to understand what was actually happening, due mainly to Python's syntax allowing two variables to be swapped on one line. I also found the variable names a little confusing.
In this example I use previous, current, tmp.
def reverse(head):
current = head
previous = None
while current:
tmp = current.next
current.next = previous # None, first time round.
previous = current # Used in the next iteration.
current = tmp # Move to next node.
head = previous
Taking a singly linked list with 3 nodes (head = n1, tail = n3) as an example.
n1 -> n2 -> n3
Before entering the while loop for the first time, previous is initialized to None because there is no node before the head (n1).
I found it useful to imagine the variables previous, current, tmp 'moving along' the linked list, always in that order.
First iteration
previous = None
[n1] -> [n2] -> [n3]
current tmp
current.next = previous
Second iteration
[n1] -> [n2] -> [n3]
previous current tmp
current.next = previous
Third iteration
# next is None
[n1] -> [n2] -> [n3]
previous current
current.next = previous
Since the while loop exits when current == None the new head of the list must be set to previous which is the last node we visited.
Edited
Adding a full working example in Python (with comments and useful str representations). I'm using tmp rather than next because next is a keyword. However I happen to think it's a better name and makes the algorithm clearer.
class Node:
def __init__(self, value):
self.value = value
self.next = None
def __str__(self):
return str(self.value)
def set_next(self, value):
self.next = Node(value)
return self.next
class LinkedList:
def __init__(self, head=None):
self.head = head
def __str__(self):
values = []
current = self.head
while current:
values.append(str(current))
current = current.next
return ' -> '.join(values)
def reverse(self):
previous = None
current = self.head
while current.next:
# Remember `next`, we'll need it later.
tmp = current.next
# Reverse the direction of two items.
current.next = previous
# Move along the list.
previous = current
current = tmp
# The loop exited ahead of the last item because it has no
# `next` node. Fix that here.
current.next = previous
# Don't forget to update the `LinkedList`.
self.head = current
if __name__ == "__main__":
head = Node('a')
head.set_next('b').set_next('c').set_next('d').set_next('e')
ll = LinkedList(head)
print(ll)
ll.revevse()
print(ll)
Results
a -> b -> c -> d -> e
e -> d -> c -> b -> a
Here is a way to reverse the list 'in place'. This runs in constant time O(n) and uses zero additional space.
def reverse(head):
if not head:
return head
h = head
q = None
p = h.next
while (p):
h.next = q
q = h
h = p
p = h.next
h.next = q
return h
Here's an animation to show the algorithm running.
(# symbolizes Null/None for purposes of animation)
Node class part borrowed from interactive python.org: http://interactivepython.org/runestone/static/pythonds/BasicDS/ImplementinganUnorderedListLinkedLists.html
I created the reversed function.
All comments in the loop of reverse meant for 1st time looping. Then it continues.
class Node():
def __init__(self,initdata):
self.d = initdata
self.next = None
def setData(self,newdata):
self.d = newdata
def setNext(self,newnext):
self.next = newnext
def getData(self):
return self.d
def getNext(self):
return self.next
class LinkList():
def __init__(self):
self.head = None
def reverse(self):
current = self.head >>> set current to head(start of node)
previous = None >>> no node at previous
while current !=None: >>> While current node is not null, loop
nextt = current.getNext() >>> create a pointing var to next node(will use later)
current.setNext(previous) >>> current node(or head node for first time loop) is set to previous(ie NULL), now we are breaking the link of the first node to second node, this is where nextt helps(coz we have pointer to next node for looping)
previous = current >>> just move previous(which was pointing to NULL to current node)
current = nextt >>> just move current(which was pointing to head to next node)
self.head = previous >>> after looping is done, (move the head to not current coz current has moved to next), move the head to previous which is the last node.
You can do the following to reverse a singly linked list (I assume your list is singly connected with each other).
First you make a class Node, and initiate a default constructor that will take the value of data in it.
class Node:
def __init__(self, data):
self.data = data
self.next = None
This solution will reverse your linked list "iteratively".
I am making a class called SinglyLinkedList which will have a constructor:
class SinglyLinkedList:
def __init__(self):
self.head = None
then I have written a method to reverse the list, print the length of the list, and to print the list itself:
# method to REVERSE THE LINKED LIST
def reverse_list_iterative(self):
prev = None
current = self.head
following = current.next
while (current):
current.next = prev
prev = current
current = following
if following:
following = following.next
self.head = prev
# Method to return the length of the list
def listLength(self):
count = 0
temp = self.head
while (temp != None):
temp = temp.next
count += 1
return count
# Method to print the list
def printList(self):
if self.head == None:
print("The list is empty")
else:
current_node = self.head
while current_node:
print(current_node.data, end = " -> ")
current_node = current_node.next
if current_node == None:
print("End")`
After that I hard code the list, and its contents and then I link them
if __name__ == '__main__':
sll = SinglyLinkedList()
sll.head = Node(1)
second = Node(2)
third = Node(3)
fourth = Node(4)
fifth = Node(5)
# Now linking the SLL
sll.head.next = second
second.next = third
third.next = fourth
fourth.next = fifth
print("Length of the Singly Linked List is: ", sll.listLength())
print()
print("Linked List before reversal")
sll.printList()
print()
print()
sll.reverse_list_iterative()
print("Linked List after reversal")
sll.printList()
Output will be:
Length of the Singly Linked List is: 5
Linked List before reversal 1 -> 2 -> 3 -> 4 -> 5 -> End
Linked List after reversal
5 -> 4 -> 3 -> 2 -> 1 -> End
I tried a different approach, in place reversal of the LList.
Given a list 1,2,3,4
If you successively swap nearby nodes,you'll get the solution.
len=3 (size-1)
2,1,3,4
2,3,1,4
2,3,4,1
len=2 (size-2)
3,2,4,1
3,4,2,1
len=1 (size-3)
4,3,2,1
The code below does just that. Outer for loop successively reduces the len of list to swap between. While loop swaps the data elements of the Nodes.
def Reverse(head):
temp = head
llSize = 0
while temp is not None:
llSize += 1
temp = temp.next
for i in xrange(llSize-1,0,-1):
xcount = 0
temp = head
while (xcount != i):
temp.data, temp.next.data = temp.next.data, temp.data
temp = temp.next
xcount += 1
return head
This might not be as efficient as other solutions, but helps to see the problem in a different light. Hope you find this useful.
Here is the whole thing in one sheet. Contains the creation of a linked list, and code to reverse it.
Includes an example so you can just copy and paste into an idle .py file and run it.
class Node(object):
def __init__(self, value, next=None):
self.value = value
self.next = next
def reverse(head):
temp = head
llSize = 0
while temp is not None:
llSize += 1
temp = temp.next
for i in xrange(llSize-1,0,-1):
xcount = 0
temp = head
while (xcount != i):
temp.value, temp.next.value = temp.next.value, temp.value
temp = temp.next
xcount += 1
return head
def printnodes(n):
b = True
while b == True:
try:
print n.value
n = n.next
except:
b = False
n0 = Node(1,Node(2,Node(3,Node(4,Node(5,)))))
print 'Nodes in order...'
printnodes(n0)
print '---'
print 'Nodes reversed...'
n1 = reverse(n0)
printnodes(n1)
def reverseLinkedList(head):
current = head
previous = None
nextNode = None
while current:
nextNode = current.nextNode
current.nextNode = previous
previous = current
current = nextNode
return previous
Most previous answers are correct but none of them had the complete code including the insert method before and and after the reverse so you could actually see the outputs and compare. That's why I'm responding to this question. The main part of the code of course is the reverse_list() method.
This is in Python 3.7 by the way.
class Node(object):
def __incurrent__(self, data=None, next=None):
self.data = data
self.next = next
class LinkedList(object):
def __incurrent__(self, head=None):
self.head = head
def insert(self, data):
tmp = self.head
self.head = Node(data)
self.head.next = tmp
def reverse_list(self):
current = self.head
prev = None
while current :
#create tmp to point to next
tmp = current.next
# set the next to point to previous
current.next = prev
# set the previous to point to current
prev = current
#set the current to point to tmp
current = tmp
self.head = prev
def print(self):
current = self.head
while current != None:
print(current.data,end="-")
current = current.next
print(" ")
lk = LinkedList()
lk.insert("a")
lk.insert("b")
lk.insert("c")
lk.print()
lk.reverse_list()
lk.print()
output:
c-b-a-
a-b-c-
Following is the generalized code to reverse a singly linked list, where head is given as function's argument:
def reverseSll(ll_head):
# if head of the linked list is empty then nothing to reverse
if not ll_head:
return False
# if only one node, reverse of one node list is the same node
if not ll_head.next:
return ll_head
else:
second = ll_head.next # get the second node of the list
ll_head.next = None # detach head node from the rest of the list
reversedLL = reverseSll(second) # reverse rest of the list
second.next = ll_head # attach head node to last of the reversed list
return reversedLL
Let me explain what I am doing here:
1) if head is null or head.next is null(only one node left in the list) return node
2) else part: take out 1st node, remove its link to rest of the list, reverse rest of the list(reverseSll(second)) and add 1st node again at last and return the list
Github link for the same
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList :
def __init__(self):
self.head = None
def add(self, data):
node = Node(data)
if not self.head:
self.head = node
else:
current = self.head
while current.next != None:
current = current.next
current.next = node
def printList(self):
value = []
if not self.head:
print("liss is Empty")
else:
current = self.head
while current:
value.append(current.data)
current = current.next
print(value)
# this func start reverse list from the last to first
def reverseLinkedList(self,node1,node2):
if self.head == None:
print("list Empty")
else:
# when we reach the last of list we link head with the last element and we disconnect head with second element that will make first element in the last of the list
if node2 == None and node1 != None:
self.head.next = None
self.head = node1
return
else:
self.reverseLinkedList(node1.next, node2.next )
node2.next = node1
ln = LinkedList()
ln.add(1)
ln.add(2)
ln.add(3)
ln.add(4)
ln.add(5)
ln.add(6)
ln.add(7)
ln.add(8)
ln.add(9)
ln.printList()
ln.reverseLinkedList(ln.head,ln.head.next)
print("after first reverse")
ln.printList()
# after i reverse list I add new item to the last
ln.add(0)
print("after add new element to the last of the list")
ln.printList()
print("after second reverse")
# i made second reverse to check after I add new element if my function work perfectly
ln.reverseLinkedList(ln.head,ln.head.next)
ln.printList()
Output :
[1, 2, 3, 4, 5, 6, 7, 8, 9]
after first reverse
[9, 8, 7, 6, 5, 4, 3, 2, 1]
after add new element to the last of the list
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
after second reverse
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Efficient way to reverse linkedlist is discussed in the below steps. Approach to reverse the linking.
Use a variable curr and equal it to head.
Use a variable prev and equal it to None.
Apply the loop with the condition that loop will run till curr is not None and in this condition use another variable next which is equal to curr.next. This will be used to get hold of next node. Now make curr.next = prev. In this way the head after reversing linkedlist will point to None. Now make prev = curr and curr = next
Code snippet
def reverse_linked_list(head):
# corner case
if head == None:
return
curr = head
# reason being orginal head after reversing should point to None
prev = None
while curr is not None:
next = curr.next
curr.next = prev
prev = curr
curr = next
# prev is returned because both curr and next will be None after reversing
return prev
There is another way to perform the task which will take time complexity as theta(n) and space complexity as theta(n). This is a recursive solution and steps are as below
Step 1: Apply the recursion for n -1 node from the end side. This means reverse the list leaving the first node.
Step 2: Link the first node with all nodes obtained from step 1 in reverse order
Code
def reverse_linked_list_recursion(head):
# corner case
if head == None:
return
if head.next == None:
return head
rest_head = reverse_linked_list_recursion(head.next)
rest_tail = head.next
rest_tail.next = head
head.next = None
return rest_head
U can use mod function to get the remainder for each iteration and obviously it will help reversing the list . I think you are a student from Mission R and D
head=None
prev=None
for i in range(len):
node=Node(number%10)
if not head:
head=node
else:
prev.next=node
prev=node
number=number/10
return head