Iteratively/Recursively create a linked list - python

Need to recursively or iteratively create a linked list for a given number string.
For example:
Number = "123"
1 -> 2 -> 3
I wrote a recursive function but doesn't seem to work, it is creating a linked list but without the middle values. 1 -> 3 instead of 1 -> 2 -> 3
def create_linked_list(head, num):
if num is "":
return head
else:
head.next = ListNode(num[0])
return create_linked_list(head.next, num[1:])
n = "123"
head = ListNode(n[0])
result = create_linked_list(head, n[1:])
while result:
print(result.val)
head = result.next
# This is printing 1 -> 4
This is the original use case
class ListNode(object):
def __init__(self, x):
self.val = x
self.next = None
n = "1234"
# I need this part of linked list creation to be done
# in a looping/recursive manner for any kind of number.
l1 = ListNode(n[0])
l1.next = ListNode(n[1])
l1.next.next = ListNode(n[2])
l1.next.next.next = ListNode(n[3])
while l1:
print(l1.val)
head = l1.next
# 1 -> 2 -> 3 -> 4

Your recursive approach looks correct. Only thing you need to do is. you don't need to return head when you reach end of number. Because you are already storing head in head variable.
Here is code that works.
class ListNode(object):
def __init__(self, x):
self.val = x
self.next = None
n = "1234"
def create_linked_list(head, num):
if num is "": #base condition.
return
else:
head.next = ListNode(num[0])
create_linked_list(head.next, num[1:])
head = ListNode(n[0])
temp = head
create_linked_list(head, n[1:])
while temp:
print(temp.val)
temp = temp.next
Output
1
2
3
4
You can also rewrite above code as following.
def create_linked_list(head, num):
if num is not "":
head.next = ListNode(num[0])
create_linked_list(head.next, num[1:])
PS: Remember to always back up your head when working with Linked Lists.

Recursion is a functional heritage and so writing our program in functional style yields the best results. This means we avoid things like mutating the list nodes, head.next = .... Your constructor should be able to set both val and next -
class node:
def __init__(self, val, next = None):
self.val = val
self.next = next
def create_llist(v = None, *vals):
if not v:
return None
else:
return node(v, create_llist(*vals))
def llist_to_str(l = None):
if not l:
return "None"
else:
return f"{l.val} -> {llist_to_str(l.next)}"
print(llist_to_str(create_llist(1, 2, 3)))
# 1 -> 2 -> 3 -> None
But create_llist and llist_to_str would probably be more consistent if we implemented them as part of the class. And maybe a better name is llist, for "linked list" -
class llist:
def __init__(self, val, next = None):
self.val = val
self.next = next
def create(v = None, *more):
if not v:
return None
else:
return llist(v, llist.create(*more))
def __str__(self):
return f"{self.val} -> {self.next}"
print(llist.create(1, 2, 3))
# 1 -> 2 -> 3 -> None
Instead of relying on side effects, functions take inputs and produce an output. As a result, notice how we our mind is free of complexity -
class llist:
# ...
def map(node = None, f = lambda x: x):
if not node:
return None
else:
return llist(f(node.val), llist.map(node.next, f))
print(llist.map(llist.create(7, 8, 9), lambda x: x * x))
# 49 -> 64 -> 81 -> None

Related

Linked list recursive delete operation: How do I change the head?

class Node:
def __init__(self, val, next=None):
self.val = val
self.next = next
def rec_delete(head, val, prev=None):
if(head == None):
return False
if(head.val == val):
if(prev == None):
head = head.next
else:
prev.next = head.next
return True
return rec_delete(head.next, val, head)
head = Node(1, Node(2, Node(3, Node(4))))
rec_delete(head, 1)
rec_delete(head, 2)
rec_delete(head, 3)
rec_delete(head, 4)
Given a linked list 1 -> 2 -> 3 -> 4 I want to remove all the elements one by one but unsure how to assign a new head in python. The issue with my current code is since head goes through a function I cannot reassign the head. I want head to be None after all the operations.
Your delete function needs to return the head of the list after val has been deleted. This not only makes the implementation of the delete much simpler (the base case is the one where the head is itself being deleted), it is necessary for the caller to be able to handle the case where the head is deleted.
class Node:
def __init__(self, val, next=None):
self.val = val
self.next = next
def __repr__(self):
"""val1 -> val2 -> val3 ..."""
return f"{self.val}" + (f" -> {self.next}" if self.next else "")
def delete(head, val):
"""Delete val from list with given head, returning head of the modified list."""
if head.val == val:
# Deleting head, so the new head is head.next.
return head.next
# Head remains head, but we still need to delete val from head.next.
head.next = delete(head.next, val)
return head
head = Node(1, Node(2, Node(3, Node(4))))
print(head) # 1 -> 2 -> 3 -> 4
head = delete(head, 1)
head = delete(head, 2)
print(head) # 3 -> 4
head = delete(head, 3)
head = delete(head, 4)
print(head) # None

Linked lists and recursion in python

I am newbie in programming and starting out in Python. My question is regarding linked lists, I wrote a class for the linked list, what I need to do is to have a function with an input as a reference pointing towards the head of the list. 'linked_list.head' as I understand, with linked_list being the name of the list in question. Specifically using recursion, I am trying to find the length of the list as the output of this function. Here's my code, I don't quite understand how I could move to the next node and return the number of nodes with recursion in this case.
import re
def special_match(strg, search=re.compile(r'[^A-Za-z.]').search):
return not bool(search(strg))
class node:
def __init__(self, data, next):
self.data = data
self.next = next
def get_data(self):
return self.data
def set_data(self,value):
self.data = value
def get_next_node(self):
return self.next
def set_next_node(self,val):
self.next = val
class linked_list:
def __init__(self):
self.head = None
self.tail = None
self.size = 0
def add_first(self,e):
newest = node(e,None)
newest.next = self.head
self.head = newest
self.size = self.size+1
if self.size == 1:
self.tail = newest
def add_last(self,e):
newest = node(e,None)
if self.size > 0:
self.tail.next = newest
else:
self.head = newest
self.tail = newest
self.size = self.size+1
def remove_first(self):
if self.size == 0:
print('The linked list is empty')
elif self.size == 1:
answer = self.head.data
self.head = None
self.tail = None
self.size -= 1
return answer
else:
answer = self.head.data
self.head = self.head.next
self.size = self.size - 1
return answer
def remove_last(self):
if self.size == 0:
print('The linked list is empty')
elif self.size == 1:
answer = self.tail.data
self.head = None
self.tail = None
self.size -= 1
return answer
else:
temp = self.head
while(temp.next is not None):
temp = temp.next
temp.next = None
def node_number(self,reference):
reference = str(reference)
count = 0
temp = self.head
if special_match(reference) == True:
count =+ 1
temp = temp.next
return self.node_number
else:
print('You have made wrong input')
def printe(self):
curr = self.head
while curr:
print(curr.data)
curr = curr.get_next_node()
if self.size == 0:
print('The list is empty')
Recursion is a functional heritage and so using it with functional style will yield the best results. In your program, you have implemented a linked list using imperative style mutable nodes- that is, the values of data and next can change over time. While this might feel like an intuitive approach, I'd like to focus on an immutable implementation that frees us from crippling state complexity. In this answer, we will implement all linked list functions using recursive forms expressed with functional styles.
We start with simple node and linked_list classes. This time we skip creating get_* and set_* functions as you have done. There's other ways to do this kind of thing in Python as we'll see in a minute
class node:
def __init__ (self, left, right):
self.left = left
self.right = right
class linked_list:
def __init__ (self, node = None):
self.node = node
Next we define primitive properties for our list: is_empty, head, and tail
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.left
#property
def tail (self):
if self.is_empty:
raise Exception ("cannot get tail of an empty list")
else:
return self.node.right
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 thru 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_first (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_first(3).add_first(2).add_first(1)
print (ls)
# 1 -> 2 -> 3 -> None
print (ls.length ())
# 3
Remember, because we've built an immutable linked list, add_first does not change the list it was called upon
ls = linked_list().add_first(3).add_first(2).add_first(1)
print (ls)
# 1 -> 2 -> 3 -> None
print (ls.add_first (0))
# 0 -> 1 -> 2 -> 3 -> None
print (ls)
# 1 -> 2 -> 3 -> None
Before we move on, let's make it easier to construct our linked lists. We add a static build function which allows us to construct a list of a varying number of inputs
class linked_list:
...
#staticmethod
def build (x = None, *rest):
if x is None:
return linked_list ()
else:
return linked_list (node (x, linked_list.build (*rest)))
print (linked_list.build (1,2,3))
# 1 -> 2 -> 3 -> None
Now, let's look at your remove_first and remove_last functions now
class linked_list:
...
def remove_first (self):
if self.is_empty:
raise Exception ("cannot remove first element of an empty list")
else:
return self.tail
def remove_last (self):
if self.is_empty:
raise Exception ("cannot remove last element of an empty list")
elif self.tail.is_empty:
return self.tail
else:
return linked_list (node (self.head, self.tail.remove_last ()))
ls = linked_list.build (1,2,3)
print (ls)
# 1 -> 2 -> 3 -> None
print (ls.remove_first ())
# 2 -> 3 -> None
print (ls.remove_last ())
# 1 -> 2 -> None
print (ls)
# 1 -> 2 -> 3 -> None
And node_number
class linked_list:
...
def node_number (self, index = 0):
if self.is_empty:
raise Exception ("index out of bounds")
elif index is 0:
return self.head
else:
return self.tail.node_number (index - 1)
ls = linked_list.build ("a", "b", "c")
print (ls.node_number (0))
# "a"
print (ls.node_number (1))
# "b"
print (ls.node_number (10))
# Exception: index out of bounds
And a add_last freebie
class linked_list:
...
def add_last (self, x):
if self.is_empty:
return self.add_first (x)
else:
return linked_list (node (self.head, self.tail.add_last (x)))
ls = linked_list.build (1, 2, 3)
print (ls)
# 1 -> 2 -> 3 -> None
print (ls.add_last (4))
# 1 -> 2 -> 3 -> 4 -> None
print (ls)
# 1 -> 2 -> 3 -> None
Full program demonstration at repl.it
I'd set it up where the length function is actually part of the Node class rather than the Linked_List class. The Linked_List class would have a length function too, but all it would do is to call the length function of the head node of the list.
Then, each node would just return the length of it's next instance plus 1.
The recursion should have a base case where the code checks if the next attribute is None. If so, the function returns the current count. If not, the counter is incremented and the function length is called as a method of the next attribute, to be able to continue the progression of the recursion along the links, which can be written as:
|val1|pointer| -> |val2|pointer| -> |val3|pointer| -> |val4|pointer| -> |val5|None|
First, below is a simpler linked list class construct for demonstration:
class Node:
def __init__(self, val=None):
self.head = val
self.next = None
def length(self, count = 0):
if self.next is None:
return count + 1 if self.next is None and self.head else count
return self.next.length(count + 1)
def insert(self, v):
if self.head is None:
self.head = v
else:
if self.next is None:
self.next = Node(v)
else:
self.next.insert(v)
#classmethod
def regular_transform(cls, node, nodes = []):
'''for easier visulization'''
return nodes+[node.head] if not node.next else cls.regular_transform(node.next, nodes+[node.head])
n = Node()
for i in [56, 232, 424, 2, 11]:
n.insert(i)
print(Node.regular_transform(n))
print(n.length())
Output:
[56, 232, 424, 2, 11]
5

Append method for linked list

class _ListNode:
def __init__(self, value, next_):
self._data = value
self._next = next_
return
class List:
def __init__(self):
self._front = None
self._count = 0
return
def _linear_search(self,key):
previous = None
current = self._front
index = 0
while current is not None and key > current._data:
previous = current
current = current._next
index += 1
if current._data != key:
previous = None
current = None
index = -1
return previous, current, index
def __contains__(self, key):
_, _, i = self._linear_search(key)
return i != -1
def append(self, value):
if self._front is None:
self._front = _ListNode(value,None)
else:
self._front._next = _ListNode(value,None)
self._count += 1
l = List()
lst = [1,2,3,4]
i = 0
n = len(lst)
while i < n:
l.append(lst[i])
i += 1
print("{}".format(l.__contains(3))
To explain more, I implement the linear search method and the contains method. The contains method check if the number is in the list or not (returns true or false). Now when I need to check that #3 in the list using contains method, the answer is false!! i cant know what's the problem
Your append method does not walk down the list. It simply always appends to self._front._next if self.front is already present. Meaning the contents at the end of the append loop are the first thing you appended, the last thing you appended and nothing in between.
To correct it walk the list looking for a _next equal to None and append there.
def append(self, value):
if self._front is None:
self._front = _ListNode(value, None)
else:
n = self._front
while n._next is not None:
n = n._next
n._next = _ListNode(value, None)
self._count += 1
You could also define a _str__ method to print the content of the List
e.g.
def __str__(self):
res = []
n = self._front
while n is not None:
res.append(str(n._data))
n = n._next
return ', '.join(res)
This is not a particularly efficient implementation as it builds an intermediate builtin list object.
You also don't need those bare return statements in your methods. You can remove those.

Use a function built outside the class on an object in Python?

I have a class
class List:
def __init__(self,head,tail):
self.head = head
self.tail = tail
def cons(self,item):
return List(item,self)
def isEmpty(self):
return self.head == None
def display(self):
s = "["
first = True
list = self
while not list.isEmpty():
if not first:
s=s+","
first = False
s=s+str(list.head)
list = list.tail
s=s+"]"
return s`
which creates a List object. I have a function (not sure if it works yet);
def sorted(list):
sort = False
i = 0
while i < range(len(list))+1:
if list[i] < list[i+1]:
sort = True
return sort
else:
return sort
and I want to run this function on the List object without adding another method to the class. I know if this was in the class it would just be List.sorted() but how can I run this function on the object without it being the objects method?
sorted(List) doesn't seem to work either. Help please.
Please, please, PLEASE: don't use sorted as a function name. There is a standard (built-in) function sorted() already, that returns a sorted version of an iterable.
Given that your code just checks to see if the List is in order, perhaps you could call it in_order or ordered or is_ascending instead?
That said, let's try to get your code working:
class Node:
def __init__(self, data=None, next=None):
self.data = data
self.next = next
def __str__(self):
return str(self.data)
class List:
def __init__(self, head:Node=None, tail:Node=None):
self.head = tail if head is None else head
self.tail = head if tail is None else tail
def cons(self, node:Node):
node.next = self.head
return List(node, self.tail)
def isEmpty(self):
return self.head == None
def display(self):
return str(self)
def __str__(self):
result = "["
first = True
n = self.head
while n is not None:
if not first:
result += ", "
result += str(n)
if n == self.tail:
break
n = n.next
first = False
result += "]"
return result
def ascendingp(self) -> bool:
n = self.head
last = None
while last != self.tail:
if last is not None and not last.data < n.data:
return False
last = n
n = n.next
return True
tests = (
(1,2,3),
(1,3,2),
(),
)
for t in tests:
last = None
first = None
for i in reversed(t):
n = Node(data=i)
first = n if first is None else first
n.next = last
last = n
l = List(head=last, tail=first)
print(str(l), "Ascending?", l.ascendingp())

Deleting a node from Linked List having "sentinels"

I am trying to write a Linked List having sentinels as per the CLRS book. My remove function for some reason removes a chunk of LL upto the node to be deleted. Attached is my code. Any suggestion will be deeply appreciated.
class Node():
def __init__(self,v):
self.value = v
self.next = None
self.prev = None
def getValue(self):
return self.value
def changeValue(self,v):
self.value = v
def getNext(self):
return self.next
def getPrev(self):
return self.prev
def setNext(self,newNext):
self.next = newNext
def setPrev(self,newPrev):
self.prev = newPrev
class List(Node):
def __init__(self):
self.nil = Node(None)
def addNode(self,v):
a = Node(v)
a.setNext(self.nil.next)
a.setPrev(self.nil)
self.nil.next = a
def length(self):
count = 0
a = self.nil
while(a.next != None):
count += 1
a = a.getNext()
return count
def search(self,v):
a = self.nil
while(a.next != None):
if (a.value == v):
return True
a = a.getNext()
return False
def remove(self,v):
a = self.nil.next
breakloop = 0
while((a.next != None) and (breakloop == 0)):
if (a.value == v):
a.prev.next = a.next
a.next.prev = a.prev
breakloop = 1
a = a.getNext()
def printList(self):
a = self.nil.next
while(a.next != None):
print(a.value)
a =a.getNext()
print(a.value)
a = List()
a.addNode(4)
a.addNode(7)
a.addNode(2)
a.addNode(6)
a.addNode(5)
a.addNode(8)
a.addNode(1)
a.addNode(14)
a.addNode(13)
a.addNode(17)
a.addNode(18)
a.printList()
a.remove(13)
a.printList()
The output will be
18 17 13 14 1 8 5 6 2 7 4
14 1 8 5 6 2 7 4
#tcaswell has correctly diagnosed the problem with the code: you're not setting the prev links on the node that used to be self.nil.next correctly. However, I think his solution is not ideal. Here's what I suggest instead:
Here's the immediate fix to the issue:
def addNode(self, v):
a = Node(v)
a.setNext(self.nil.next)
self.nil.next.setPrev(a) # this is the link that was previously missing
a.setPrev(self.nil)
self.nil.setNext(a)
However, that won't work correctly when the list is empty, since self.nil.next is None at the start. We can fix it though, by making self.nil link to itself when we create it in the List constructor:
def __init__(self):
self.nil = Node(None)
self.nil.next = self.nil.prev = self.nil # set up circular links!
Now, self.nil will always have a valid node as it's next and prev values.
You will need to change your removeNode and printList loops to check for self.nil rather than None.
The bug is in your addNode function, the .prev node for all of your nodes is self.nil
Using the following:
def addNode(self,v):
a = Node(v)
a.setNext(self.nil.next)
if self.nil.next is not None:
self.nil.next.setPrev(a)
a.setPrev(self.nil)
self.nil.next = a
will fix your problem. You probably want to put this logic in the setPrev and setNext functions (to make sure a == a.next.prev and a == a.prev.next at all times for all a except the ends).

Categories