Making a linked list without built in functions - python

I have a project to make a linked list in python.
My program needs to add to the list, remove from it and get elements. Sounds easy right? Wrong! We aren't allowed to use normal lists or built-in functions (other than the basic print, str...)
I have one problem with my code, I have to initialise a blank list then add the elements, 1 by 1. Everything else works fine.
My questions:
Is this how a normal python list works?
Is it possible to add items to a linked list with a loop? (without another list)
Here's the code:
class Node: # the node class
def __init__(self, cargo = None, next = None): # __init__ stands for initialize
self.cargo = cargo # e.g. steve
self.next = next # represents the next node or None if its the last
def __str__(self): # __str__ is called when the node is printed or converted to a string
return str(self.cargo) # return a string
class List: # the main list class
def __init__(self): # default is to initialize an empty list
self.first_node = None
self.last_node = None
self.length = 0
def get(self, position, length): # function for efficiency
if position == "end":
position = length - 1 # last
if position > length - 1: # can't go beyond last
raise ValueError("List index out of range")
prv_node = self.first_node
node = self.first_node # start at the first
num = 0
while num < position: # go up to position
prv_node = node # remember the previous node
node = node.next # next node!
num = num + 1
return prv_node, node, position
def add_node(self, cargo, position = "end"): # adds a node
prv_node, node, position = self.get(position, self.length + 1) # +1 because the length is being increased
print("adding node at "+str(position)+": "+str(cargo))
if position == 0: # first
self.first_node = Node(cargo, next = self.first_node) # the first node is the new node
if self.length == 0: # first node to be added
self.last_node = self.first_node # there is only one node
elif position == self.length: # last
self.last_node.next = Node(cargo, next = None) # last_node.next was None, it is now a new node
self.last_node = self.last_node.next # last node is now the new last node
else: # normal
prv_node.next = Node(cargo, next = node) # stick it in between
self.length = self.length + 1 # length is now + 1
def get_node(self, position): # gets a node
...
def remove_node(self, position): # removes a node
...
def __str__(self): # when the list is printed
node = self.first_node # start from the first
string = ""
while node != self.last_node: # go to the end
string = string + str(node) + ", " # print each node
node = node.next
string = string + str(self.last_node) # last node hasn't been added yet
return string
# initialize
mylist = List()
mylist.add_node("steve")
mylist.add_node("james")
mylist.add_node("tom")
mylist.add_node("david")
mylist.add_node("hoe-yin")
mylist.add_node("daniel")
print(mylist)
[EDIT] second question re-phrased

Here's how Python lists are implemented in CPython: http://www.laurentluce.com/posts/python-list-implementation/
If you have your values in some other iterable, then yes:
for item in list_of_items:
mylist.add_node(item)

Related

Deleting items in a specified index range for linked list

In my linked list, I wrote a function drop_between which deletes nodes in a specified range.
everything other than drop_between function works fine.
My expected output:
sample = Deque()
sample.push_front(3)
sample.push_front(2)
sample.push_front(1)
sample.push_front(0)
linked list = [0, 1, 2, 3]
sample.drop_between(1,3)
linked list = [0, 3] # 1, 2 removed
However, my function removes everything that is specified in the drop_between except the very first number that is passed in (which is the start).
My linked list function file:
class Node:
"""
Initialize empty node
"""
def __init__(self, data, prev = None, next = None):
self.data = data
self.next = next
self.prev = prev
class Deque:
"""
A double-ended queue
"""
def __init__(self):
"""
Initializes an empty Deque
"""
self.head = None
self.tail = None
self.size = 0
def __len__(self):
"""
Computes the number of elements in the Deque
:return: The size of the Deque
"""
return self.size
def push_front(self, e):
"""
Inserts an element at the front of the Deque
:param e: An element to insert
"""
new_head = Node(data = e, next = self.head)
if len(self) == 0:
self.tail = new_head
if self.head:
self.head.prev = new_head
self.head = new_head
self.size += 1
def drop_between(self, start, end): #need help with this function
"""
Deletes elements from the Deque that within the range [start, end)
:param start: indicates the first position of the range
:param end: indicates the last position of the range(does not drop this element)
"""
cur_index = 0
if (start > end):
raise IndexError
if (start < 0):
raise IndexError
curr = self.head
while curr.next:
last_node = curr
curr = curr.next
if ((cur_index >= start) and (cur_index < end)):
print("here", cur_index)
last_node.next = curr.next.next
curr.next.next.prev = last_node.next
cur_index += 1
def listprint(self, node):
"""
Prints each element of the node front to back
:param node:
"""
while (node is not None):
print(node.data)
last = node
node = node.next
My main file:
def main():
D = Deque()
D.push_front(9)
D.push_front(8)
D.push_front(7)
D.push_front(6)
D.push_front(5)
D.push_front(4)
D.push_front(3)
D.push_front(2)
D.push_front(1)
D.push_front(0)
D.drop_between(4,7)
D.listprint(D.head)
The output of my main displays the numbers 0-4 and 7-9 inclusive, but the output of 4 was unexpected. How am I able to properly unlink the 4 in my linked list?
Please, note that collections already have a implementation of deque
With that in mind, your task ends up really simple:
from collections import deque
def drop_between(d, start, end):
d.rotate(-start)
for __ in range(end-start):
d.popleft()
d.rotate(+start)
d = deque(n for n in range(20))
print(d)
drop_between(d, 5, 9)
print(d)
However, if you are not allowed to use this external source, I advise to code a similar logic.
Replace your drop_between function with this:
def drop_between(self, start, end): #need help with this function
"""
Deletes elements from the Deque that within the range [start, end)
:param start: indicates the first position of the range
:param end: indicates the last position of the range(does not drop this element)
"""
cur_index = 0
if (start > end):
raise IndexError
if (start < 0):
raise IndexError
#assumption: start node != head
prev_to_start_node = self.get_node_by_index(start-1)
end_node = self.get_node_by_index(end)
prev_to_start_node.next = end_node
end_node.prev = prev_to_start_node
def get_node_by_index(self,index):
i = 0
curr = self.head
while i < index and curr.next:
curr = curr.next
i+=1
return curr
Notice that I added get_node_by_index, so if you wish to remove it, you'll need to replace the code accordingly.

How to delete a "node" which is passed to a method in a single linked list using Python

I want to implement 5 ways of deleting a node in a single linked list.
Delete the first element in the list - Easy
Delete the last element in the list - Easy
Delete the element at a position(numeric) - Easy
Delete the element with the given value - Easy
Delete a specific node - Not sure how to do this
I guess the challenge I am facing is how to find the memory address of the node or how to pass the memory address of the node to the method. The following is the code I have come up with. Obviously the " def delete_node(self, node):" does not work. The following is the code I have come up with so far.
from Node import Node
class SingleLinkedList:
"""Constructor. Sets the length of the linkedlist to zero and initializes head reference"""
def __init__(self):
self.head = None
self.length = 0
""" Method to get the length of the list """
def get_list_length(self):
return self.length
""" Method to INSERT a node at the beginning of the list """
def insert_at_beginning(self, data):
new_Node = Node()
new_Node.set_data(data)
if self.length == 0:
self.head = new_Node
else:
new_Node.set_next(self.head)
self.head = new_Node
self.length += 1
""" Method to INSERT a node at the end of the list """
def insert_at_end(self, data):
new_Node = Node()
new_Node.set_data(data)
if self.length == 0:
self.head = new_Node
else:
current = self.head
while current.has_next():
current = current.get_next()
current.set_next(new_Node)
self.length += 1
""" Method to INSERT a node at the given position, i.e. after postion - 1 . Position count start at 0 """
def insert_at_position(self, position, data):
if position > self.length or position < 0:
return None
else:
if position == 0:
self.insert_at_beginning(data)
else:
if position == self.length:
self.insert_at_end(data)
else:
new_Node = Node()
new_Node.set_data(data)
current = self.head
count = 0
while count < (position - 1):
current = current.get_next()
count += 1
new_Node.set_next(current.get_next())
current.set_next(new_Node)
self.length += 1
""" Method to INSERT a new node to the list. Default insertion at the end of the list """
def add(self, data):
self.insert_at_end(data)
""" Method to PRINT the elements of the list """
def print_list(self):
if self.length == 0:
return "Linked List is empty"
else:
current = self.head
while current.has_next():
print str(current.get_data()) + " ---> ",
current = current.get_next()
print str(current.get_data())
""" Method to DELETE the node at the beginning of the list """
def delete_at_beginning(self):
if self.length == 0:
return "List is empty"
else :
self.head = self.head.get_Next()
self.length -= 1
""" Method to DELETE the node at the end of the list """
def delete_at_end(self):
if self.length == 0:
return "List is empty"
else:
current = self.head
previous = None
while current.has_next():
previous = current
current = current.get_next()
previous.set_Next(None)
self.length -= 1
""" Method to DELETE a node at the given position, i.e. after postion - 1 . Position count start at 0 """
def delete_at_position(self, position):
if position > self.length or position < 0:
return "Position does not exist"
else:
if position == 0:
self.delete_at_beginning()
elif position == self.length:
self.delete_at_end()
else:
count = 0
current = self.head
previous = None
while count < position:
previous = current
current = current.get_next()
count += 1
previous.set_next(current.get_next())
self.length -= 1
""" Method to DELETE a node with a given value """
def delete_value(self, value):
if self.length == 0:
print " List is empty "
else:
current = self.head
previous = None
while current.has_next():
if current.get_data() == value:
break
previous = current
current = current.get_next()
if current.get_data() != value:
print "Item " + str(value) + " not in the list"
else:
previous.set_next(current.get_next())
self.length -= 1
def delete_node(self, node):
if self.length == 0:
print "List is empty"
else:
current = self.head
previous = None
found = False
while not found:
if current == node:
found = True
elif current is None:
print "Node not in the list"
return
else:
previous = current
current = current.get_next()
if previous is None:
self.head = current.get_next()
else:
previous.set_next(current.get_next())
self.length -= 1
def main():
l = SingleLinkedList()
print l.get_list_length()
l.add(1)
l.add(2)
l.add(3)
l.print_list()
l.insert_at_beginning(500)
l.insert_at_beginning(600)
l.insert_at_beginning(700)
l.print_list()
l.insert_at_position(3, 99999)
l.print_list()
l.delete_at_position(3)
l.print_list()
l.delete_value(500)
l.print_list()
nd = Node()
nd.set_data(2)
l.delete_node(nd)
l.print_list()
if __name__ == '__main__':
main()
I am following a book on Data Structures written in C++ and translating it to Python. I guess it is easy to pass the memory address in C++, maybe this is not doable using Python?
Any help will be much appreciated.
Thanks
EDIT:
I have another challenge related to this class. I want to be able to find the length/size of the linked list both iteratively and recursively. Finding the length iteratively is straight-forward. How do I find the length recursively? I am able to visualize recursive approach in my head, but unable to code this in Python. Also, this is confusing as self is the first method in the parameter.
def sizeByIteration(self):
current = self.head
counter = 0
while current is not None:
counter += 1
current = current.get_next()
return counter
# def sizeByRecursion(self):
# if self.head is None:
# return 0
# else:
# self.head = self.head.get_next()
# return 1 + self.sizeByRecursion()
You may want to try is instead of ==. is will return True if two variables reference the same object. Whereas == will use a default comparator that compares the value of the objects.
Try this instead:
def delete_node(self, node):
if self.length == 0:
print "List is empty"
else:
current = self.head
previous = None
found = False
while not found:
if current is node:
found = True
elif current is None:
print "Node not in the list"
return
else:
previous = current
current = current.get_next()
if previous is None:
self.head = current.get_next()
else:
previous.set_next(current.get_next())
self.length -= 1
Also as a note: the benefit of python is that you can write very short, concise, and functional code. Take advantage of recursion if you understand the method. If you aren't at that point in university yet, don't worry about this and continue on your merry way.
To call deleted_node() need to find node, that you can only do by traversing the list from head.
So instead of traversing twice, at first traversal itself we can delete node
Also, to find length by recursion
The logic written by you modifies the entire list, instead this will work
def sizeByRecursion(self, node):
if node is None:
return 0
return self.sizeByRecursion(node.get_next()) + 1

How to implement insert method in a doubly linked list?

I need to implement this insert function in my doubly linked list and I'm having trouble getting it to properly insert elements at given indexes. I am able to add an element into an empty list object, but when I attempt to add a new node at the last node, I get an error saying:
'NoneType' object has no attribute 'setPrev'
I understand what this error means and have tried shifting my function around to avoid this error and get the right output, but to no avail.
Question: How can I fix this insert function in order to allow it to add nodes in all cases?
class DLLNode:
def __init__(self,initdata):
self.data = initdata
self.next = None
self.prev = None
def __str__(self):
return str(self.data)
def getData(self):
return self.data
def getNext(self):
return self.next
def getPrev(self):
return self.prev
def setData(self, new_data):
self.data = new_data
def setNext(self, new_next):
self.next = new_next
def setPrev(self, new_prev):
self.prev = new_prev
class DLL:
""" Class representing a doubly-linked list. """
def __init__(self):
""" Constructs an empty doubly-linked list. """
self.head = None
self.size = 0
def __str__(self):
""" Converts the list into a string representation. """
current = self.head
rep = ""
while current != None:
rep += str(current) + " "
current = current.getNext()
return rep
def isEmpty(self):
""" Checks if the doubly-linked list is empty. """
return self.size <= 0
def insert(self, item, index):
""" Inserts a node at the specified index. """
# Construct node.
current = self.head
n = DLLNode(item)
# Check index bounds.
if index > self.size:
return 'index out of range'
# If the list is empty...
if self.isEmpty():
self.head = n
self.head.setPrev(self.head)
# If the index is the first node...
if index == 0:
n.setNext(self.head)
self.head = n
if self.size == 0:
self.prev = n
# If the index is the last node...
elif index == self.size:
n.next.setPrev(n)
# If the index is any other node...
else:
if current == None:
n.setPrev(self.prev)
self.prev.setNext(n)
self.prev = n
else:
n.setNext(current)
n.getPrev().setNext(n)
current.setPrev(n.getPrev())
n.setPrev(n)
self.size += 1
A testcase is the following scenario:
l = DLL()
l.insert(88, 0)
l.insert(99, 1)
l.insert(77, 2)
l.insert(55, 3)
l.insert(34, 1)
l.insert(3, 0)
l.insert(15, 6)
l.insert(100, 8)
print("list after inserts", l)
output is as follows:
Index out of range.
list after inserts 3 88 34 99 77 55 15 """
The problem is that n is a DLLNode you construct yourself. By default prev and next are set to Null; therefore you cannot call any methods on them.
def insert(self, item, index):
""" Inserts a node at the specified index. """
# Construct node.
current = self.head
n = DLLNode(item)
# Check index bounds.
if index > self.size:
return 'index out of range'
# If the list is empty...
if self.isEmpty():
self.head = n
self.head.setPrev(self.head)
else : #added else case to prevent overlap
for x in range(0,index-1): #Obtain the current
current = current.next #move to the next item
# If the index is the first node...
if index == 0:
n.setNext(self.head)
self.head = n
if self.size == 0:
self.prev = n
# If the index is the last node...
elif index == self.size:
current.setNext(n) #set n to be the next of current
n.setPrev(current) #set current to be the previous of n
# If the index is any other node...
else:
n.setNext(current.next)
n.setPrev(current)
if current.next != None :
current.next.setPrev(n)
current.setNext(n)
self.size += 1
The last situation works as follows:
/------\|
C N X
|\------/
with C the currentXthenextofcurrentandNthen(new node). First we set theprevandnextofn`:
/------\|
C <--N-->X
|\------/
Now we check whether X actually is a real node (although this is strictly not necessary, since "last nodes" are handled above). If X is not None, we set the prev of X to N:
/------\|
C <--N-->X
|\-/
Finally we do not longer need C to point to X (otherwise we could not call functions of X), so we set the next of C to N:
/--\|
C <--N-->X
|\-/
Can you provide test data to test if the implementation works correctly?
I believe the problem is here
elif index == self.size:
n.next.setPrev(n)
When insert at the last element, you need to traverse to the current last element say last. Assume you did that you can do
elif index == self.size:
last.setNext(n)
n.setPrev(last)
n.setNext(head) #only if this list is also circular
self.size++

Adding a count and an index in my LinkedList

I need to add an index and a count function for my program but I am really confused on how to go about this because my teacher is very broad. Any ideas that I could do for adding an index and a count function into my Linked List?
Here's my code:
from ListNode import ListNode
class LinkedList(object):
#--------------------------------------------------------------
def __init__(self, seq=()):
""" Pre: Creates a Linked List
Post: Creates a list containing the items in the seq=()"""
if seq == ():
# If there is no items to be put into the list, then it creates an empty one.
self.head = None
else:
# Creates a node for the first item.
self.head = ListNode(seq[0], None)
# If there are remaining items, then they're added while keeping track of the last node.
last = self.head
for item in seq[1:]:
last.link = ListNode(item, None)
last = last.link
self.size = len(seq)
#-------------------------------------------------------------
def __len__(self):
'''Pre: Nothing.
Post: Returns the number of items in the list.'''
return self.size
#-------------------------------------------------------------
def _find(self, position):
'''This is a private method, which means it only works in this class.
This returns the last node used. (0 is the first item, size-1 is the last item)
Pre: 0 (less than or equal to) position (less than) self.size
Post: Returns the ListNode at the specified position in the list.'''
assert 0 <= position < self.size
node = self.head
# move forward until we reach the specified node
for i in range(position):
node = node.link
return node
#-------------------------------------------------------------
def append(self,x):
'''This adds (Appends) 'x' onto the end of the list
Post: X is appended to the end of the list.'''
# First create a new node containing x
newNode = ListNode(x)
# This will link it onto the end of the list.
if self.head is not None:
# Not an empty list
node = self._find(self.size - 1)
node.link = newNode
else:
# If it is an empty list.
# You will set self.head to the new node
self.head = newNode
self.size += 1
#-------------------------------------------------------------
def __getitem__(self, position):
''' returns the data item at the location position
Pre: 0 <= position < size
Post: Returns data item at the specified position.'''
node = self._find(position)
return node.item
#-------------------------------------------------------------
def __setitem__(self, position, value):
''' Sets the data item at the location position to the value.
Pre: 0 <= position < self.size
Post: Sets the data item at the specified position to value.'''
node = self._find(position)
node.item = value
#--------------------------------------------------------------
def __delitem__(self, position):
''' Deletes the item at the location position from the list.
Pre: 0 <= position < self.size
Post: The item at the specified position is removed from the list.'''
assert 0 <= position < self.size
self._delete(position)
#--------------------------------------------------------------
def __max__(self):
''' Goes through each node and compares what the max is for the linked list.
Post: Finds the max of the linked list and returns that value.'''
max_value = self.head.item
node = self.head.next
while node is not None:
if node.item > max_value:
max_value = node.item
node = node.link
return max_value
#--------------------------------------------------------------
def __min__(self):
''' Goes through each node and compares what the min is for the linked list.
Post: Finds the min of the linked list and returns that value.'''
min_value = self.head.item
node = self.head.next
while node is not None:
if node.item < min_value:
min_value = node.item
node = node.link
return min_value
#--------------------------------------------------------------
def _delete(self, position):
''' This is a private function where it deletes an item at the location
position from the list.
Pre: 0 <= position < self.size
Post: The item at the specified location is removed from the list.
The item is then returned ( To be used with pop.)'''
if position == 0:
# Save the item from the initial node
item = self.head.item
# Change the self.head to point "over" the deleted node.
self.head = self.head.link
else:
# Find the node before the one that you are deleting.
prev_node = self._find(position - 1)
# Save the item from the node you are deleting.
item = prev_node.link.item
# Change the previous node to go over the deleted node. (Example 2 goes to 4)
prev_node.link = prev_node.link.link
self.size -= 1
return item
#--------------------------------------------------------------
def pop(self, i = None):
''' This returns and removes whatever is at position 'i' from the list. It is
defaulted to return and remove the last item.
Pre: self.size > 0 and ((i is None or (0 <= i < self.size))
Post: If I is None, then the last item in the list is removed and then returned.
Otherwise, the item at position 'i' is removed and returned.'''
assert self.size > 0 and (i is None or (0 <= i < self.size))
# The default is to delete the last item in the list.
# 'i' could be zero so we need to compare to None.
if i is None:
i = self.size - 1
return self._delete(i)
#-----------------------------------------------------------------
def insert(self, i, x):
''' Inserts 'x' at the position 'i' is at in the list.
Pre: 0 <= i <= self.size
Post: x is inserted into the list at position 'i', and the old segment
from position 'i' (oldsize-1) are now at position 'i'+1 (newsize - 1).'''
assert 0 <= i <= self.size
if i == 0:
# Inserting before ) requires changing/updating self.head.
self.head = ListNode(x, self.head)
else:
# Find the item that this node will be inserted after.
node = self._find(x, self.head)
node.link = ListNode(x, node.link)
self.size += 1
#-----------------------------------------------------------------
def __copy__(self):
''' Post: Returns a new Linked List object that is a shallow copy of self.'''
a = LinkedList()
node = self.head
while node is not None:
a.append(node.item)
node = node.link
return a
#-----------------------------------------------------------------
def __iter__(self):
return LinkedListIterator(self.head)
#---------------------------------------------------------------------
class LinkedListIterator(object):
#-----------------------------------------------------------------
def __init__(self, head):
self.currnode = head
#-----------------------------------------------------------------
def next(self):
if self.currnode is None:
raise StopIteration
else:
item = self.currnode.item
self.currnode = self.currnode.link
return item
This may seem basic for you guys but I am struggling to figure out what my teacher wants me to index or count in this program.
The best would be to look at python's documentation of those methods:
[].index.__doc__
[].count.__doc__

Reversing a linked list in python

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

Categories

Resources