0
0
DSA Pythonprogramming

Delete from End of Doubly Linked List in DSA Python

Choose your learning style9 modes available
Mental Model
To remove the last item, we find the tail and unlink it from the list, updating the previous node to be the new tail.
Analogy: Imagine a train of connected carriages. To remove the last carriage, you detach it from the one before it, so the second last becomes the new end.
head -> 1 ↔ 2 ↔ 3 ↔ 4 ↔ 5 ← tail
Each arrow ↔ shows two-way links between nodes.
Dry Run Walkthrough
Input: list: 1 ↔ 2 ↔ 3 ↔ 4 ↔ 5, delete from end
Goal: Remove the last node (5) and update the list tail to node 4
Step 1: Access tail directly (O(1) since tail pointer maintained)
head -> 1 ↔ 2 ↔ 3 ↔ 4 ↔ 5 ↑tail
Why: Tail pointer gives direct access to last node
Step 2: Capture deleted_data = tail.data # 5
head -> 1 ↔ 2 ↔ 3 ↔ 4 ↔ 5 ↑tail
Why: Save data before unlinking node
Step 3: tail = tail.prev # move tail to node 4
head -> 1 ↔ 2 ↔ 3 ↔ 4 ↑tail  5
Why: Update tail to point to new last node
Step 4: tail.next = None # unlink old tail (5)
head -> 1 ↔ 2 ↔ 3 ↔ 4 ↑tail
5 is removed
Why: Sever forward link to fully remove node
Result:
head -> 1 ↔ 2 ↔ 3 ↔ 4 ← tail
Deleted node: 5
Annotated Code
DSA Python
class Node:
    def __init__(self, data):
        self.data = data
        self.prev = None
        self.next = None

class DoublyLinkedList:
    def __init__(self):
        self.head = None
        self.tail = None

    def append(self, data):
        new_node = Node(data)
        if not self.head:
            self.head = new_node
            self.tail = new_node
            return
        self.tail.next = new_node
        new_node.prev = self.tail
        self.tail = new_node

    def delete_from_end(self):
        if not self.tail:  # empty list
            return None
        deleted_data = self.tail.data
        if self.head == self.tail:  # single node
            self.head = None
            self.tail = None
            return deleted_data
        # unlink last node
        self.tail = self.tail.prev
        self.tail.next = None
        return deleted_data

    def __str__(self):
        nodes = []
        curr = self.head
        while curr:
            nodes.append(str(curr.data))
            curr = curr.next
        return ' ↔ '.join(nodes) + ' ← tail'

# Driver code
dll = DoublyLinkedList()
dll.append(1)
dll.append(2)
dll.append(3)
dll.append(4)
dll.append(5)
print("Before deletion:", dll)
deleted = dll.delete_from_end()
print(f"Deleted node: {deleted}")
print("After deletion:", dll)
if not self.tail: # empty list
check if list is empty to avoid errors
if self.head == self.tail: # single node
handle case where only one node exists
self.tail = self.tail.prev
move tail pointer back to previous node
self.tail.next = None
unlink the old tail node from the list
OutputSuccess
Before deletion: 1 ↔ 2 ↔ 3 ↔ 4 ↔ 5 ← tail Deleted node: 5 After deletion: 1 ↔ 2 ↔ 3 ↔ 4 ← tail
Complexity Analysis
Time: O(n) because we traverse from head to tail to find the last node if tail pointer is not maintained; here tail pointer is maintained so O(1) for deletion
Space: O(1) because no extra space is used besides a few pointers
vs Alternative: Without a tail pointer, deletion from end requires O(n) traversal; with tail pointer, deletion is O(1)
Edge Cases
empty list
delete_from_end returns None and list remains empty
DSA Python
if not self.tail:  # empty list
single node list
deletes the only node and sets head and tail to None
DSA Python
if self.head == self.tail:  # single node
When to Use This Pattern
When you need to remove the last element quickly from a doubly linked list, use the tail pointer to delete in O(1) time.
Common Mistakes
Mistake: Not updating the tail pointer after deletion
Fix: Always move tail to tail.prev and set tail.next to None
Mistake: Not handling empty or single node list cases
Fix: Add checks for empty list and single node list before deletion
Summary
Deletes the last node from a doubly linked list by unlinking it and updating the tail.
Use when you want to remove the last element efficiently from a doubly linked list.
The key is to update the tail pointer and unlink the last node to maintain list integrity.