How to delete last Node of the list using next - python

I try to remove last Node from the list but get following error no matter how I twist it: --- line 108, in remove_last
before.nxt = delete.nxt
AttributeError: 'NoneType' object has no attribute 'nxt'---
Here is my code:
#dataclass
class Node:
value: int = None
nxt: Any = None
#dataclass
class Deque:
head: Node = None
tail: Node = None
size: int = 0
def remove_last(self):
if self.head is None:
print("empty queue")
return None
else:
before = self.head
for i in range(self.size-1):
before = before.nxt
delete = before.nxt
before.nxt = delete.nxt
self.size -= 1
return before.value
Why can I not apply next?

I think you miscounted and forgot about the singleton case:
def remove_last(self):
if self.head is None: # empty
print("empty queue")
return None
if self.head is self.tail: # one element (there can still be no `before`)
val = self.head.value
self.head = self.tail = None
self.size = 0
return val
before, delete = self.head, self.head.nxt
while delete.nxt: # why rely on size (but it should be size-2 iterations)
before, delete = before.nxt, delete.nxt
before.nxt = None
self.size -= 1
return delete.value
As indicated in the comments, the general case case would require size-2 iterations. Simplest case: 2 elements, then before would be self.head, which means 0 iterations.

This is how I solved it. It was None because I was jumping to the next node after last node, which didn't exist
else:
node = self.head
for i in range(self.size-2):
node = node.nxt
node.nxt = None

Related

Singly linked list. Implementation of the Get method - getting an element by index

from typing import Any, Optional
class Node:
def __init__(self, value: Optional[Any] = None, next: Optional['Node'] = None) -> None:
self.value = value
self.next = next
def __str__(self) -> str:
return 'Node [{value}]'.format(
value=str(self.value)
)
class LinkedList:
def __init__(self) -> None:
self.head: Optional[Node] = None
self.length = 0
def __str__(self) -> str:
if self.head is not None:
current = self.head
values = [str(current.value)]
while current.next is not None:
current = current.next
values.append(str(current.value))
return '[{values}]'.format(values=' '.join(values))
return 'LinkedList []'
def append(self, elem: Any) -> None:
new_node = Node(elem)
if self.head is None:
self.head = new_node
return
last = self.head
while last.next:
last = last.next
last.next = new_node
self.length += 1
def remove(self, index) -> None:
cur_node = self.head
cur_index = 0
if self.length == 0 or self.length <= index:
raise IndexError
if cur_node is not None:
if index == 0:
self.head = cur_node.next
self.length -= 1
return
while cur_node is not None:
if cur_index == index:
break
prev = cur_node
cur_node = cur_node.next
cur_index += 1
prev.next = cur_node.next
self.length -= 1
my_list = LinkedList()
my_list.append(10)
my_list.append(20)
my_list.append(30)
print('Current list:', my_list)
# print('Getting the third element:', )
print('Removing the second element.')
my_list.remove(1)
print('New list:', my_list)
Result:
Current list: [10 20 30]
Getting the third element: 30
Removing the second element.
New list: [10 30]
In a singly linked list, a link is a link only to the next element, that is, it can only move towards the end of the list.
It is impossible to find out the address of the previous element based on the contents of the current node.
Tell me how to implement getting an element by index. And get index 2 (30) ?
Tell me how to implement getting an element by index.
Your instructor is inviting you to
def get(self, index: int) -> Node:
and then flesh out the definition.
You will find the definition of remove(self, index) already
offers all that you need.
Simply traverse the list in readonly manner,
without changing any .next attributes.
Though you may find it simpler to just use a for i in range(index):
loop, never bothering to examine self.length.
If a user tries e.g. .get(99), running off the end of the list,
it's unclear what the proper result should be.
Maybe an exception?
You might have latitude to specify what correct behavior would be.
And get index 2 ?
Once def get is correctly defined,
it's a simple call:
assert my_list.get(2).value == 30

Python Circular Queue using Linked List

I'm trying to implement a circular queue (without limited buffer) in python.
When I call display after enqueue, it doesn't work. However, it works fine when called in other cases.
Its implementation is similar to the get_size function which works as expected.
Below is the implementation:
class Node(object):
def __init__(self, value):
self.value = value
self.next = None
class LinkedCircularQueue(object):
def __init__(self, head=None, tail=None):
self.head = head
self.tail = tail
def enqueue(self, item):
"""
Add the node to the back of the queue and set its next pointer to
self.head
"""
if self.tail is not None:
self.tail.next = item
else:
self.head = item
self.tail = item
item.next = self.head
return self.tail.value
def dequeue(self):
"""
Remove the oldest node (from the front) by copying the value and
making the preceding node as the new head
"""
if self.head is not None:
deleted = self.head.value
self.head = self.head.next
else:
deleted = None
print("Circular queue is empty !!")
return deleted
def display(self):
"""
Traverse from front to back and show elements
"""
front = self.head
back = self.tail
if front is not None and back is not None:
while back.next != front:
print(front.value, end=" ")
front = front.next
else:
print("Circular queue is empty !!")
def get_size(self):
"""
Traverse from front to back and count elements
"""
size = 0
if self.head is not None and self.tail is not None:
while self.tail.next != self.head:
size += 1
self.head = self.head.next
return size
def peek_front(self):
front = self.head
return front.value
def peek_back(self):
back = self.tail
return back.value
def is_empty(self):
first = self.head
last = self.tail
if first is None and last is None:
return True
else:
return False
def main():
# Initialize elements
element1 = Node(1)
element2 = Node(2)
element3 = Node(3)
element4 = Node(4)
element5 = Node(5)
linked_circular_queue = LinkedCircularQueue()
# Initial tests
linked_circular_queue.display()
print(linked_circular_queue.is_empty())
print(linked_circular_queue.get_size())
print()
# Test enqueue
linked_circular_queue.enqueue(element5)
linked_circular_queue.enqueue(element3)
linked_circular_queue.enqueue(element1)
linked_circular_queue.enqueue(element4)
linked_circular_queue.enqueue(element2)
linked_circular_queue.display() # doesn't work
print()
# Test dequeue
linked_circular_queue.dequeue()
linked_circular_queue.dequeue()
linked_circular_queue.display()
print()
# Test peek
print(linked_circular_queue.peek_front())
print(linked_circular_queue.peek_back())
print()
# Final tests
print(linked_circular_queue.is_empty())
print(linked_circular_queue.get_size())
if __name__ == '__main__':
main()
Current Output:
Circular queue is empty !!
True
0
1 4 2
1
2
False
3
Expected Output:
Circular queue is empty !!
True
0
5 3 1 4 2
1 4 2
1
2
False
3
Change the while loop from the display function to this:
while back != front:
print(front.value, end=" ")
front = front.next
print(back.value) # print(front.value) also works

Why do I get AttributeError: 'NoneType' object has no attribute 'value'?

Below is my code in python. I'm basically trying to look through a linked list to see if a specific element is in that list. The code works if the item is in the list, but not if it doesn't. I believe the problem lies within the loop coming to the end of the list and the last node, but I'm not sure how to fix the error. Any help would be appreciated. (Edited to include the classes used)
class Node:
def __init__(self, data):
#raise error for wrong data input type
if not type(data) in [int, float, str]:
raise TypeError("data must be an integer, float, or string")
self.value = data
class LinkedListNode(Node):
def __init__(self, data):
Node.__init__(self, data) # Use inheritance to set self.value.
self.next = None # Reference to the next node.
self.prev = None # Reference to the previous node.
class LinkedList:
def __init__(self):
self.head = None
self.tail = None
self.length = 0
def append(self, data):
# Create a new node to store the input data.
new_node = LinkedListNode(data)
if self.head is None:
# If the list is empty, assign the head and tail attributes to
# new_node, since it becomes the first and last node in the list.
self.head = new_node
self.tail = new_node
self.length += 1
else:
# If the list is not empty, place new_node after the tail.
self.tail.next = new_node # tail --> new_node
new_node.prev = self.tail # tail <-- new_node
# Now the last node in the list is new_node, so reassign the tail.
self.tail = new_node
self.length += 1
def find(self, data):
x = range(self.length)
current_position = self.head.value
current_node = self.head
for i in x:
if current_position == data:
return self.head
else:
current_node = current_node.next
current_position = current_node.value
if current_position != data:
raise ValueError("data point is not in the list")
return

Add Node function not working singly linked list python

I'm a Noob, struggling to understand and implement a singly linked list, that adds items at the tail. I believe the only code that is not working is the add function, which I can't figure out the logic for. I believe I want to set the first node to be the head, and then insert each other element at the tail, changing the pointer for head to point to the 2nd item when adding it, then the pointer for the 2nd item to point to the third etc., but can't figure out how to go about coding that (to deal with an unknown number of strings, here 3 for simplicity.
strings = ["one", "two", "three"]
class Node:
def __init__(self,data,nextNode=None):
# populate the Node, with data and pointer
self.data = data
self.nextNode = nextNode
def getData(self):
# method to get value of this node
return self.data
def setData(self,val):
# set value of node to val
self.data = val
def getNextNode(self):
# get the pointer to the next node
return self.nextNode
def setNextNode(self,val):
# set pointer to the next node
self.nextNode = val
class LinkedList:
def __init__(self, head = None, tail = None):
# initial properties of linked list, size 0
self.head = head
self.tail = tail
self.size = 0
def getSize(self):
# get size of linked list
return self.size
def addNode(self,data):
# Head should point to first node, which will have a value, and a Null pointer
if (self.size == 0):
newNode = Node(data, self.tail)
self.head.getNextNode() = newNode
else:
# All additional nodes should be inserted at tail, and with the pointers for the prior nodes changed to point to the new node
newNode = Node(data, self.tail)
self.tail = newNode
self.size += 1
return True
def printNode(self):
curr = self.head
while curr:
print(curr.data)#, curr.nextNode)
curr = curr.getNextNode()
mylist = LinkedList()
for i in strings:
mylist.addNode(i)
mylist.printNode()
# desired output: Head -> one --> two --> three/Tail
There were many little mistakes, please find them in code below. And let me know if you don't understand something.
One important change is a new node shouldn't have access to its next node. Its already the last node, so there can't be any node next to it. Also please pay close attention to else block of addNode function.
strings = ["one", "two", "three","four","five"]
class Node:
def __init__(self,data):
# populate the Node, with data and pointer
self.data = data
self.nextNode = None
def getData(self):
# method to get value of this node
return self.data
def setData(self,val):
# set value of node to val
self.data = val
def getNextNode(self):
# get the pointer to the next node
return self.nextNode
def setNextNode(self,val):
# set pointer to the next node
self.nextNode = val
class LinkedList:
def __init__(self, head = None, tail = None):
# initial properties of linked list, size 0
self.head = head
self.tail = tail
self.size = 0
def getSize(self):
# get size of linked list
return self.size
def addNode(self,data):
# Head should point to first node, which will have a value, and a Null pointer
if (self.size == 0):
self.head = Node(data)
self.tail = self.head
self.size = 1
else:
# All additional nodes should be inserted at tail, and with the pointers for the prior nodes changed to point to the new node
newNode = Node(data)
self.tail.nextNode = newNode
self.tail = newNode
self.size += 1
return True
def printNode(self):
curr = self.head
while curr:
print(curr.data)#, curr.nextNode)
curr = curr.getNextNode()
mylist = LinkedList()
for i in strings:
mylist.addNode(i)
mylist.printNode()

Unexpected output when popping last element of linked list

I have made a Node and Deque class to represent a double linked list. I wrote a function to pop the last item of my list, but after executing the function it pops the first element instead.
My expected output:
my_list.push_front(1)
my_list.push_front(2)
my_list.push_front(3)
linked list is [3, 2, 1]
my_list.pop_back() --> [3,2]
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.size = 1
def __len__(self):
"""
Computes the number of elements in the Deque
:return: The size of the Deque
"""
counter = 1
current = self.head
if self.head is None:
return 0
while current.next is not None:
counter += 1
current = current.next
return counter
def push_front(self, e): #needs work
"""
Inserts an element at the front of the Deque
:param e: An element to insert
"""
new_head = Node(data = e, next = self.head)
if self.head:
self.head.prev = new_head
self.head = new_head
def pop_back(self):
"""
Removes and returns the last element
:return: The (former) last element
"""
if self.head == None:
raise IndexError
curr = self.head
while curr.next:
curr = curr.next
save = self.head.data
self.head = self.head.next
self.size -= 1
return save
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():
my_list = Deque()
my_list.push_front(1)
my_list.push_front(2)
my_list.push_front(3)
my_list.pop_back()
my_list.listprint(my_list.head) #print elements in the list
In my pop_back() function, I was thinking of traversing until the end of the linked list, and then set self.head to self.head.next and decrease the size of the linked list by 1.
Here's what I think is the issue:
save = self.head.data
self.head = self.head.next
You want to remove the last one, but you're actually changing the reference for the head. If you want to change the reference of the last one, you should be doing:
while curr.next.next: # This allows you to stand on the previous of the last one
curr = curr.next
save = curr.next
curr.next = None
self.size -= 1
return save
The actual thing you're doing there it's a pop and not a dequeue

Categories