I have made a function that reverses the singly linked list using Recursive method.
However I am having some difficulty executing my below code:
class node:
def __init__(self,data=None):
self.next=None
self.data=data
class linked_list:
def __init__(self):
self.head=node()
def append(self,data):
new_node=node(data)
cur_node=self.head
while (cur_node.next!=None):
cur_node=cur_node.next
cur_node.next=new_node
return cur_node.data
def display(self):
elements=[]
cur_node=self.head
while(cur_node.next!=None):
cur_node=cur_node.next
elements.append(cur_node.data)
print(elements)
def reverseRecursive(self,prev_code,cur_node):
if cur_node.next!=None:
reverseRecursive(cur_node,cur_node.next)
cur_node.next=prev_node
else:
self.head=cur_node
return
lst1=linked_list()
lst1.display()
lst1.append(1)
lst1.append(3)
lst1.append(5)
lst1.append(7)
lst1.display()
lst1.reverseRecursive(None,_____)
lst1.display()
What should I pass the second argument in reverseRecursive function/method so that I can execute it?
As a second argument, I want to simply pass the head node of a linked list. But I don't know how to get the head node from the init method of the class linked_list
I have tried several things but I'm not able to resolve it. Maybe I am not very good at OOP concepts. Can anyone please help me in resolving this?
The linked list is a recursive structure, and so using it with functional style will yield the best results. In your program, you have implemented a linked list using procedural style and mutable nodes – you change the values of data and next over time. While this might feel like an intuitive approach, I'd like to focus on an immutable discipline that frees us from crippling state complexity.
First, we fix the node constructor function. We set both properties when constructing new nodes because they will not change later in the program –
class node:
def __init__ (self, data, next):
self.data = data
self.next = next
Then a linked_list is just a single node constructed by a particular convention:
node.data hold's the node's data
node.next is either:
another linked_list
or, None, representing the end of the list
We begin with the constructor for linked_list –
class linked_list:
def __init__ (self, node = None):
self.node = node
# ...
And implement is_empty, head, and tail properties to abstract away node –
class linked_list:
def __init__ (self, node = None):
self.node = node
#property
def is_empty (self):
return self.node is None
#property
def head (self):
if self.is_empty:
raise Exception ("cannot get head of an empty list")
else:
return self.node.data
#property
def tail (self):
if self.is_empty:
raise Exception ("cannot get tail of an empty list")
else:
return self.node.next
Now the use of a node is completely abstracted, and we can write higher level list behaviors by using our new properties –
class linked_list:
...
def length (self):
if self.is_empty:
return 0
else:
return 1 + self.tail.length()
Above, we see it's very easy to talk about our list through use of its properties. Before we go further, let's see how we can construct lists and visualize them using print. For object-to-string conversion, we use __str__ –
class linked_list:
...
def add (self, x):
return linked_list (node (x, self))
def __str__ (self):
if self.is_empty:
return "None"
else:
return str (self.head) + " -> " + str (self.tail)
ls = linked_list().add('A').add('B').add('C')
print (ls)
# C -> B -> A -> None
print (ls.length())
# 3
Remember, because we've built an immutable linked list, add does not change the list it was called upon –
ls = linked_list().add('A').add('B').add('C')
print (ls)
# C -> B -> A -> None
print (ls.add('D'))
# D -> C -> B -> A -> None
print (ls)
# C -> B -> A -> None
Finally, we can implement reverse –
class linked_list:
# ...
def reverse (self):
def loop (ls, acc):
if ls.is_empty:
return acc
else:
return loop (ls.tail, acc.add(ls.head))
return loop (self, linked_list())
ls = linked_list().add('A').add('B').add('C')
print (ls)
# C -> B -> A -> None
print (ls.reverse())
# A -> B -> C -> None
Reversing the list does not mutate it
print (ls)
# C -> B -> A -> None
print (ls.reverse())
# A -> B -> C -> None
print (ls)
# C -> B -> A -> None
Related
I'm creating a List class in python (a List like java lists) using generics. The class node is also generic and I'm creating the getters and setters methods for the prev and next node. I was wondering how could I return a type like the class node itself?
This is my progress:
from typing import Generic, TypeVar
T = TypeVar('T')
class Node(Generic[T]):
''' Generic class Node. It models a node for a linked list. '''
def __init__(self, element: T) -> None:
''' Constructor. It recives an element of type T.'''
self.element = element
self.next = None
self.prev = None
def get_item(self) -> T:
''' Returns the item in the node.'''
return self.element
def get_prev(self) -> #What is the type I should return here?:
''' Returns the previous node.'''
return self.prev
def get_next(self) -> #What is the type I should return here?:
''' Return the next node.'''
return self.next
def set_prev(self, prev) -> None:
''' Changes the previous element to the specified node.'''
self.prev = prev
def set_next(self, next) -> None:
''' Changes the next element to the specified node.'''
self.next = next
I've tried with
def get_prev(self) -> Node[T]:
''' Returns the previous node.'''
return self.prev
def get_next(self) -> Node[T]:
''' Return the next node.'''
return self.next
But it gives me the error
Traceback (most recent call last):
File "List.py", line 5, in <module>
class Node(Generic[T]):
File "List.py", line 18, in Node
def get_prev(self) -> Node[T]:
NameError: name 'Node' is not defined
I think the newest Python versions have the capability of self-referencing classes in type annotations (here, get_prev's return type Node that is currently being defined).
Older Python versions, down to 3.7, still support it by adding:
from __future__ import annotations
see: https://peps.python.org/pep-0563/#enabling-the-future-behavior-in-python-3-7
I am doing a class project and I have to implement an unbounded singly linked list using python. I need to implement a given 'insert' that has to consider the following cases...
insert into an empty queue
insert at the front of the queue
insert after some existing node.
This is the class given in python and i need to implement the insert function given at the bottom.
I am new to this so any help would be greatly appreciated!
class CinemaPriorityQueue:
"""A linked list implementation of an unbounded min-priority queue."""
class Node:
"""A node in a linked list."""
def __init__(self, item: object, priority_value: int) -> None:
"""Initialise the node with the given item and priority value."""
self.item = item
self.priority = priority_value
self.next = None
def __init__(self) -> None:
"""Initialise the queue to be empty."""
self.head = None
def is_empty(self) -> bool:
"""
Preconditions: true
Postconditions: the output is true if the queue is empty, false otherwise
"""
return self.head == None
def print(self) -> None:
"""Print out the queue"""
if self.head == None:
print('The queue is empty')
else:
current = self.head
while current != None:
print(current.item, current.priority)
current = current.next
def insert(self, item: object, priority_value: int) -> None:
"""Insert item according to priority.
Preconditions: true
Postconditions: post-self is the sequence
pre-self with item inserted after
the last item in self with the same priority
"""
pass
#*Write your code solution here*
I can tell you the idea behind the solution. In the singly linked list, while adding a new element, compare it with the elements in the linked list and add it where it fits so that the linked list is sorted. This will give you a min priority queue.
Python 3 - I am new to coding and am finding recursion difficult. I'm making a linked list class with recursive methods for adding and removing items from the list. Right now, I am unable to remove an item if it happens to be the first item in my list. I wrote some alternative code which could remove the first item from the list if I included another parameter (previous) and another base case, but then I could only remove the first item and spent way too long trying to figure out why so I scrapped that entirely. I would appreciate a hint!
Also, I am already aware that I have getters and am not using them properly.
class Node:
"""
Represents a node in a linked list
"""
def __init__(self, data):
self._data = data
self._next = None
def get_data(self):
"""getter method for data in Node class"""
return self._data
def get_next(self):
"""getter method for next in Node class"""
return self._next
class LinkedList:
"""
A linked list implementation of the List ADT
"""
def __init__(self):
self._head = None
def get_head(self):
"""getter function for head of list"""
return self._head
def add(self, val):
""" Adds a node containing val to the linked list - helper function"""
self._head = self.recursive_add(self._head, val)
def recursive_add(self, node1, val):
""" Adds a node containing val to the linked list """
if node1 is None:
return Node(val)
else:
node1._next = self.recursive_add(node1._next, val)
return node1
def remove(self, val):
"""removed the node containing val from the linked list - helper function"""
self.recursive_remove(self._head, val)
def recursive_remove(self, node1, val):
"""
Removes the node containing val from the linked list
"""
if node1 is None:
return node1
elif node1._data == val:
return node1._next
else:
node1._next = self.recursive_remove(node1._next, val)
return node1
def main():
my_list = LinkedList()
my_list.add(13)
my_list.add(9)
my_list.add(5)
my_list.remove(9)
if __name__ == '__main__':
main()
def remove(self, val):
"""removed the node containing val from the linked list - helper function"""
if self._head and self._head._data == val:
self._head = self._head._next
return
self.recursive_remove(self._head, val)
if its at the start, the head needs to be changed.
In remove you call recursive_remove, but ignore its return value. You should use it as the (potentially different) _head reference, must like is done in the recursive method itself, where you have:
node1._next = self.recursive_remove(node1._next, val)
# ^ │
# └───────────────────────────────────┘
Note how node1._next is passed as argument, and the method's return value is the (potentially different) reference that node1._next should end up with. The same pattern should be applied in the initial call in remove:
def remove(self, val):
self._head = self.recursive_remove(self._head, val)
# ^ │
# └──────────────────────────────────┘
NB: the same pattern is used in add, where you do it correctly.
I tried to write a code that protects the pointer of a linked list. The setter should point only to an instance which belongs to the same class. Usually isinstance() or type() work after the class is defined. But the setter is a method inside that class, hence the class is not fully defined yet.
I have no doubt that type() gives out error. But I wonder why isinstance(instance, class) yields False if calling from another class.
#define the Node class
class Node:
"""Class Node contain only data and a next pointer variables."""
def __init__(self, Data = None):
self.data = Data
self.__next = None
def getNext(self):
"""The getter"""
return self.__next
def setNext(self, NextNode):
"""The setter"""
#if possible check if NewNode is an instance of Node before pointing to it.
#I have tried "isinstance(), type(), etc. but failed.
if isinstance(NextNode, Node):
self.__next = NextNode
else:
print('The Next pointer should point to "Node" only.')
Then check if isinstance is working
ANode = Node((1,2,3))
BNode = Node((5,6))
ANode.setNext(BNode)
print(BNode)
print(ANode.getNext())
Both prints yield the same address
<__main__.Node object at 0x112162828>
<__main__.Node object at 0x112162828>
So everything looks fine. But When I call from the LinkedList class, printed below, the isinstance yields False, as seen from my warning.
class LinkedList:
"""This class is the Linked List of Node."""
def __init__(self, FirstNode = None):
"""Initialize by creating an empty List. __First hold the pointer that point to the first node."""
if FirstNode is None:
self.__first = Node(None)
self.__last = self.__first
elif type(FirstNode) is Node:
self.__first = FirstNode
self.__last = self.__first
else:
print('To create a linked-list enter nothing or a Node.')
raise TypeError
def getFirst(self):
return self.__first
def append(self, NewLastNode):
"""Add LastNode to the end of the list."""
if not isinstance(NewLastNode,Node):
raise TypeError
OldLast = self.__last
OldLast.setNext(NewLastNode)
self.__last = NewLastNode
NewLastNode.setNext(None)
def removeFirstNode(self):
"""Remove the first node (when the buffer is full)."""
OldFirst = self.__first
NewFirst = OldFirst.getNext()
if NewFirst == None:
# just clear data
OldFirst.data = None
else:
self.__first = NewFirst
del OldFirst
Then I create an instance of the LinkedList class
LL = LinkedList(Node((1,2)))
NewNode = Node((2.0, 3.0, -10))
Surely isinstance works fine here
isinstance(NewNode,Node)
yields True, but
LL.append(NewNode)
which will call Node.setNext() and there the isinstance() yields False as the else in Node.setNext() prints out
The Next pointer should point to "Node" only.
The piece of code that's giving you the error is this:
NewLastNode.setNext(None)
because you're trying to set the next element to an object that it's not a Node instance, hence the error.
I think you could simply remove this statement, as your self.__last is now correctly pointing to your NewLastNode. So your code will become:
def append(self, NewLastNode):
"""Add LastNode to the end of the list."""
if not isinstance(NewLastNode,Node):
raise TypeError
OldLast = self.__last
OldLast.setNext(NewLastNode)
self.__last = NewLastNode
I'm writing an implementation of doubly linked lists. In order to traverse the list, I'm using something like:
class Node:
""" A node in our linked list """
def __init__(self, value: Any, next: Union['Node', None] =None,
previous: Union['Node', None] =None) -> None:
self.value = value
self.next = next
self.previous = previous
...
def __next__(self, direction: int =1) -> Union['Node', None]:
if direction == 1:
return self.get_next()
else:
return self.get_previous()
...
where get_next and get_previous are just getters of self.next and self.previous.
However, PyCharm yells at me for trying to call next as
next(some_node, direction=-1). What's the proper way to do this?
Besides __iter__ there is also __reversed__. Both are required to return iterators. The __next__ method should be implemented on iterators (not on node-classes). Note that all magic methods (when called by a function like next instead of directly invoked) need to implement the expected arguments not more - not less.
For example a doubly linked list could just implement __iter__ and __reversed__ and rely on next and previous attribute of the Node:
class Node(object):
def __init__(self, val, nxt, prv):
self.val = val
self.nxt = nxt
self.prv = prv
class DoublyLinkedList(object):
def __init__(self, base=None, last=None):
self.base = base
self.last = last
def prepend(self, val):
new = Node(val, self.base, None)
if self.base is None:
self.base = new
self.last = new
else:
self.base.prv = new
self.base = new
def append(self, val):
new = Node(val, None, self.last)
if self.last is None:
self.base = new
self.last = new
else:
self.last.nxt = new
self.last = new
def __iter__(self):
current = self.base
while current is not None:
yield current
current = current.nxt
def __reversed__(self):
current = self.last
while current is not None:
yield current
current = current.prv
For example:
dl = DoublyLinkedList()
dl.prepend(10)
dl.prepend(20)
dl.prepend(30)
for i in dl:
print(i.val)
gives:
30
20
10
similar for reversed:
for i in reversed(dl):
print(i.val)
# prints:
10
20
30
__next__ is part of the iterator protocol and should be used as described in said protocol, doing otherwise only make problems with the rest python.
In your case just rename the function to simple next and use as some_node.next(-1), though I would change the direction argument to a boolean, as that is how you use it, and its name too. Like this for example
class None:
...
def next(self, forward:bool=True) -> Union['Node', None]:
if forward:
return self.get_next()
else:
return self.get_previous()
and use as some_node.next(), some_node.next(False) or even some_node.next(0) (using 0 instead of False for the same effect)
The extra argument to next is a default value, and __next__ doesn't take any extra arguments. Python doesn't have any sort of two-way iterators. If your interface is not exactly the same as for i in obj:, then you should write your own.