A complete working Python program to demonstrate all stack operations using a doubly linked list  stack  Stack  stack.isempty True  stack.printstack stack elements are:  for i in range4: ...     stack.pushi ...  stack.isempty False  stack.printstack stack elements are: 3210  stack.top 3  lenstack 4  stack.pop 3  stack.printstack stack elements are: 210 add a Node to the stack if self.head is None: self.head  Nodedata else: newnode  Nodedata self.head.prev  newnode newnode.next  self.head newnode.prev  None self.head  newnode def popself  T  None: return the top element of the stack return self.head.data if self.head is not None else None def lenself  int: temp  self.head count  0 while temp is not None: count  1 temp  temp.next return count def isemptyself  bool: return self.head is None def printstackself  None: printstack elements are: temp  self.head while temp is not None: printtemp.data, end temp  temp.next Code execution starts here if name  main: Start with the empty stack stack: Stackint  Stack Insert 4 at the beginning. So stack becomes 4None printStack operations using Doubly LinkedList stack.push4 Insert 5 at the beginning. So stack becomes 45None stack.push5 Insert 6 at the beginning. So stack becomes 456None stack.push6 Insert 7 at the beginning. So stack becomes 4567None stack.push7 Print the stack stack.printstack Print the top element printnTop element is , stack.top Print the stack size printSize of the stack is , lenstack pop the top element stack.pop pop the top element stack.pop two elements have now been popped off stack.printstack Print True if the stack is empty else False printnstack is empty:, stack.isempty
# A complete working Python program to demonstrate all
# stack operations using a doubly linked list

from __future__ import annotations

from typing import Generic, TypeVar

T = TypeVar("T")


class Node(Generic[T]):
    def __init__(self, data: T):
        self.data = data  # Assign data
        self.next: Node[T] | None = None  # Initialize next as null
        self.prev: Node[T] | None = None  # Initialize prev as null


class Stack(Generic[T]):
    """
    >>> stack = Stack()
    >>> stack.is_empty()
    True
    >>> stack.print_stack()
    stack elements are:
    >>> for i in range(4):
    ...     stack.push(i)
    ...
    >>> stack.is_empty()
    False
    >>> stack.print_stack()
    stack elements are:
    3->2->1->0->
    >>> stack.top()
    3
    >>> len(stack)
    4
    >>> stack.pop()
    3
    >>> stack.print_stack()
    stack elements are:
    2->1->0->
    """

    def __init__(self) -> None:
        self.head: Node[T] | None = None

    def push(self, data: T) -> None:
        """add a Node to the stack"""
        if self.head is None:
            self.head = Node(data)
        else:
            new_node = Node(data)
            self.head.prev = new_node
            new_node.next = self.head
            new_node.prev = None
            self.head = new_node

    def pop(self) -> T | None:
        """pop the top element off the stack"""
        if self.head is None:
            return None
        else:
            assert self.head is not None
            temp = self.head.data
            self.head = self.head.next
            if self.head is not None:
                self.head.prev = None
            return temp

    def top(self) -> T | None:
        """return the top element of the stack"""
        return self.head.data if self.head is not None else None

    def __len__(self) -> int:
        temp = self.head
        count = 0
        while temp is not None:
            count += 1
            temp = temp.next
        return count

    def is_empty(self) -> bool:
        return self.head is None

    def print_stack(self) -> None:
        print("stack elements are:")
        temp = self.head
        while temp is not None:
            print(temp.data, end="->")
            temp = temp.next


# Code execution starts here
if __name__ == "__main__":
    # Start with the empty stack
    stack: Stack[int] = Stack()

    # Insert 4 at the beginning. So stack becomes 4->None
    print("Stack operations using Doubly LinkedList")
    stack.push(4)

    # Insert 5 at the beginning. So stack becomes 4->5->None
    stack.push(5)

    # Insert 6 at the beginning. So stack becomes 4->5->6->None
    stack.push(6)

    # Insert 7 at the beginning. So stack becomes 4->5->6->7->None
    stack.push(7)

    # Print the stack
    stack.print_stack()

    # Print the top element
    print("\nTop element is ", stack.top())

    # Print the stack size
    print("Size of the stack is ", len(stack))

    # pop the top element
    stack.pop()

    # pop the top element
    stack.pop()

    # two elements have now been popped off
    stack.print_stack()

    # Print True if the stack is empty else False
    print("\nstack is empty:", stack.is_empty())
