reverse a linked list non recursive - python-3.x

Please check the reverse function below. The rest of the code should be fine. The function is not reversing the doubly linked list for some reason.
#!/bin/python3
import math
import os
import random
import re
import sys
Doubly linked list Node structure
class DoublyLinkedListNode:
def __init__(self, node_data):
self.data = node_data
self.next = None
self.prev = None
Doubly linked list structure
class DoublyLinkedList:
def __init__(self):
self.head = None
self.tail = None
def insert_node(self, node_data):
node = DoublyLinkedListNode(node_data)
if not self.head:
self.head = node
else:
self.tail.next = node
node.prev = self.tail
self.tail = node
Prints the doubly linked list from head to the tail in order.
def print_doubly_linked_list(node, sep, fptr):
while node:
fptr.write(str(node.data))
node = node.next
if node:
fptr.write(sep)
Please check the below reverse function as this function does not return the reversed doubly linked list. Check for any errors and let me know.
def reverse(head):
if head == None:
return head
temp = None
curr = head
while(curr is not None):
temp = curr.prev
curr.prev = curr.next
curr.next= temp
curr = curr.next
if temp is not None:
head = temp.prev
return head
if __name__ == '__main__':
fptr = open(os.environ['OUTPUT_PATH'], 'w')
t = int(input())
for t_itr in range(t):
llist_count = int(input())
llist = DoublyLinkedList()
for _ in range(llist_count):
llist_item = int(input())
llist.insert_node(llist_item)
llist1 = reverse(llist.head)
print_doubly_linked_list(llist1, ' ', fptr)
fptr.write('\n')
fptr.close()

You start reversing your list from the head, which has no prev item and therefore breaks out of your while loop. Instead, reversing from the tail should do:
llist1 = reverse(llist.tail)
In general, I think your function reverse should take the whole list (not the head or tail) as an argument, and then build a completely new DoublyLinkedList from the items in it. That would also solve the confusion with your variable names, where llist is a DoublyLinkedList while llist1 is a DoublyLinkedListNode.
edit:
I forgot, in insert_node, you should also make self.tail = node if there hasn't been a head yet / first node.

Related

how to make this code short for reverse circular LL in python

class node:
def __init__(self,data):
self.data = data
self.next = None
class circularLL:
def __init__(self):
self.head = None
self.tail = None
def insertNode(self,data):
newnode = node(data)
if self.head is None:
self.head = newnode
self.tail = newnode
else:
newnode.next = self.head
tail = self.tail
tail.next = newnode
self.tail = tail.next
def printCLL(self):
current = self.head
while current.next is not None and current.next is not self.head:
print(current.data, end="----")
current = current.next
print(current.data)
def reverseCLL(self):
head = self.head
tail = self.tail
if head == tail:
return
else:
count = 0
while head.next is not tail:
count +=1
if count ==1:
next = head.next
prev = head
head.next = tail
newtail = head
head = next
else:
next = head.next
head.next = prev
prev = head
head = next
if count is not 0:
next = head.next
head.next = prev
prev = head
tail.next = prev
self.head = tail
self.tail = newtail
else:
head.next = tail
self.tail.next = head
self.head = tail
self.tail = head
c = circularLL()
c.insertNode(1)
c.printCLL()
c.insertNode(2)
c.insertNode(3)
c.insertNode(4)
c.insertNode(5)
c.insertNode(6)
c.printCLL()
c.reverseCLL()
c.printCLL()
I have written a code for circular linkedlist. but I think the reverse part can be shorter so how to make the reverse part short ? and what are the alternative to do this ???
and can any one tell me when I am using the assignment operator for a object then that variable is pointing to that original object or the object copy is assign to the variable's memory location ??
There are still some issues in your code:
When the first node is added, that node's next reference is left to None, which means the list is not really circular. You should actually never have a node whose next reference is None, so I'd suggest to change the Node constructor so that it doesn't assign that value, but instead makes the node self referencing (self.next = self). That also means you can remove most of the None checks from your code.
The printCLL method fails when the list is empty. It should first check that condition.
You should not use is not when comparing with a literal. So instead do if count != 0: or even if count:
Some other remarks:
It is common practice to use PascalCase for class names, so Node instead of node and CircularLL instead of circularLL.
As in a circular, non-empty list the head node is always the one after the tail node, there is no real need to store a separate reference to the head node. You just need self.tail.
As the class name already clearly indicates that we're dealing with a circular linked list, there is no need to have the CLL suffix in the method names. And for a similar reason I'd call the insert method just insert.
Instead of providing a print method, it is probably better practice to provide a __repr__ method, which the native print function will call when it exists.
Make a linked list instance iterable by defining an __iter__ method. Then the above __repr__ can also rely on that.
As to the core of your question: yes this code for reversing a list can be greatly reduced. There is no need to have a counter.
Proposed code:
class Node:
def __init__(self,data):
self.data = data
self.next = self
class CircularLL:
def __init__(self):
self.tail = None
def insert(self, data):
newnode = Node(data)
if self.tail:
newnode.next = self.tail.next
self.tail.next = newnode
self.tail = newnode
def __iter__(self):
if not self.tail:
return
current = self.tail
while current.next is not self.tail:
current = current.next
yield current.data
yield current.next.data
def __repr__(self):
return "----".join(map(repr, self))
def reverse(self):
tail = self.tail
if not tail:
return
prev = tail
curr = prev.next
self.tail = curr
while curr != tail:
curr.next, prev, curr = prev, curr, curr.next
curr.next = prev
c = CircularLL()
c.insert(1)
print(c)
c.insert(2)
c.insert(3)
c.insert(4)
c.insert(5)
c.insert(6)
print(c)
c.reverse()
print(c)

Wrapper Class in Python for Linked List

I am absolutely new to Wrapper Classes in Python. I was trying to implement it in a program of linked list where multiple linked list are in use. My code is:
def nodewrap(cls):
class Nodewrap:
def __init__(self):
self.head = None
self.tail = None
return Nodewrap
#nodewrap
class Node:
def __init__(self,data):
self.data = data
self.next = None
class Intersection:
def addnode(self,d):
newnode = Node(d)
if head == None:
head = tail = newnode
else:
tail.next = newnode
tail = newnode
obj1 = Intersection()
obj2 = Intersection()
obj3 = Intersection()
s1 = int(input("Enter size of 1st list : \n"))
for i in range(s1):
obj1.addnode(int(input("Enter the data : \n")))
s2 = int(input("Enter size of 1st list : \n"))
for i in range(s2):
obj2.addnode(int(input("Enter the data : \n")))
temp1 = obj1.head
for i in range(s1):
temp2 = obj2.head
for j in range(s2):
if temp1.data == temp2.data:
obj3.addnode(temp1.data)
break
temp2 = temp2.next
temp1 = temp1.next
print("Intersection is :")
temp = obj3.head
while temp!=None:
print(temp.data,end=" ")
temp = temp.next
I thought of using a wrapper class to wrap the class Node instead of using objects of the class Intersection only with data fields as head, tail. But it is giving me some sort of error with regards to init().
Please help.
I was trying to learn it from here:
https://www.geeksforgeeks.org/wrapper-class-in-python/
I think I understand what you want to do, but I think that you don't want to use a decorator, but you want to inherit from NodeWrap class
class Nodewrap:
head = None
tail = None
class Node(NodeWrap):
def __init__(self,data):
self.data = data
self.next = None
But I don't see any reason why to inherit this way. This should be enough, for a linked list. I have added is_first and is_last property
from __future__ import annotations
class Node:
prev_node = None
next_node = None
def __init__(self, data):
self.data = data
def add_node(self, node: Node) -> None:
if self.prev_node is not None:
raise ValueError('Previous node already defined.')
self.next_node = node
node.prev_node = self
#property
def is_first(self) -> bool:
return self.prev_node is None
#property
def is_last(self) -> bool:
return self.next_node is None
You can implement next, iter and create an Iterator class.
I don't recommend using next as the variable name.
from __future__ import annotations reference here. It's just for self reference annotation.

Understanding the "self" in classes for Python

I'm trying to understand the solution provided for reversing a linked list. In particular, I don't get why for the very last line we write:
self.head=prev
and not
current=prev
since
current=self.head
I know my reasoning is flawed, that's why I came here for help. Thank you in advance.
class Node:
# Constructor to initialize the node object
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
# Function to initialize head
def __init__(self):
self.head = None
def reverse(self):
prev = None
current = self.head
while(current is not None):
next = current.next
current.next = prev
prev = current
current = next
self.head = prev
= is not equality like in math, it is the assignment/binding operator.
Therefore, after:
current=self.head
current=prev
current will have the value of prev and self.head will have nothing to do with current nor will be modified.

Is there one variable way to create single linked list in python

So I have the below single linked list class:
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
and now I create a single linked list from an array [-10,-3,0,5,9]
input = [-10,-3,0,5,9]
head = ListNode(input[0])
for idx, x in enumerate(input[1:]):
if idx == 0:
head.next = ListNode(x)
temp = head.next
else:
temp.next = ListNode(x)
temp = temp.next
Let's check my implementation:
while (head):
print(head.val)
head = head.next
the output is
-10
-3
0
5
9
now the output is correct. But as you saw, I used some ugly way of creating a single linked list instance, i.e., I used two variables: temp and head. Is there any way I can use only head or temp?
Here is a decent implementation of a singly linked list, with a separate class for ListNode and SinglyLinkedList, in which the ListNode is a node in a singly-linked list whereas SinglyLinkedList is the singly-linked list which also supports the operations like prepend and append.
class ListNode:
"""
A node in a singly-linked list.
"""
def __init__(self, data=None, next=None):
self.data = data
self.next = next
def __repr__(self):
return repr(self.data)
class SinglyLinkedList:
def __init__(self):
"""
Create a new singly-linked list.
Takes O(1) time.
"""
self.head = None
def __repr__(self):
"""
Return a string representation of the list.
Takes O(n) time.
"""
nodes = []
curr = self.head
while curr:
nodes.append(repr(curr))
curr = curr.next
return '[' + ', '.join(nodes) + ']'
def prepend(self, data):
"""
Insert a new element at the beginning of the list.
Takes O(1) time.
"""
self.head = ListNode(data=data, next=self.head)
def append(self, data):
"""
Insert a new element at the end of the list.
Takes O(n) time.
"""
if not self.head:
self.head = ListNode(data=data)
return
curr = self.head
while curr.next:
curr = curr.next
curr.next = ListNode(data=data)
if __name__ == '__main__':
singly_linked_list = SinglyLinkedList()
print(singly_linked_list)
input_array = [-10, -3, 0, 5, 9]
for x in input_array:
print(x)
singly_linked_list.append(x)
print(singly_linked_list)
Other implementations for the singly-linked list can be seen here.
Hope it helps.

Cant insert item at start of linked list - python

I'm currently learning about linked lists for a class and ran into trouble.
I have to be able to insert an item before a specified item so
(Apple,banana,pear)before pear would be (Apple,banana,newItem,pear)
and I managed this with this code:
def insert_before(head,data,location):
current = head
found = False
while not found:
if current.next.data == location:
new_node = Node(data)
new_node.next = current.next
current.next = new_node
found = True
else:
current = current.next
But my issue arose when trying to insert an item before the first item in the list, to try this I thought of doing it as such:
if head.data == location:
new_node = Node(data)
head.next = head.next
new_node.next = head`
But this doesn't seem to work. Any guides I found on here were to add an item AFTER the first item, any tips would be appreciated.
In the provided source code, the use of head.next = head.next do nothing and doesn't change the value of the head node.
To modify the value of the first node in a linked list by inserting a new node before, it is necessary update the head variable.
Solution 1 - assign the head as the returned value of the insert_before() function.
The variable previous is used to modify the node before and when is
= None, the first node must be modified.
def insert_before(head,data,location):
current = head
previous = None
found = False
while not found:
if (current != None):
if (current.data == location):
new_node = Node(data)
if (previous != None):
new_node.next = previous.next
previous.next = new_node
else:
new_node.next = head
head = new_node
found = True
else:
previous = current
current = current.next
else:
print('location ',location,' not found.')
break
return head
The use of the function becomes:
myhead = Node(5)
print(myhead.data) # >> 5
myhead = insert_before(myhead,3,5)
print(myhead.data) # >> 3
print(myhead.next.data) # >> 5
Solution 2 - use the OOP of Python by adding a headattribute in the Node class.
The OOP approach is quite similar, but instead of storing the head
node outside the function, the function insert_before() is added to
the class Node.
Step 1 - add in the class Node the attribute head.
class Node(object):
def __init__(self, data=None, next_node=None):
self.data = data
self.next = next_node
self.head = self # store the first node
Step 2 - use the internal self.head instead of the head as parameter
In that case, when the new node shall be inserted before the first
node, the assignment is very simple self.head = new_node.
def Insert_Before(self,data,location):
current = self.head
previous = None
found = False
print('insert ',data,' before ',location)
while not found:
if (current != None):
if (current.data == location):
new_node = Node(data)
if (previous != None):
new_node.next = previous.next
previous.next = new_node
else:
new_node.next = self.head
self.head = new_node # update the first node
found = True
else:
previous = current
current = current.next
else:
print('location ',location,' not found.')
break
return
The use of the function becomes:
myhead = Node(5)
print(myhead.data)
myhead.insert_before(3,5)
print(myhead.head.data)
print(myhead.head.next.data)
Warning: instead of using myhead as the first node, use the
myhead.head attribute.

Resources