Python Program to Implement a Stack Using Linked List

Stacks are linear data structures that follow the Last-In-First-Out (LIFO) principle, which states that the item that was most recently added is the one that gets deleted first. A stack's fundamental commands are "push", "pop", "peek" (or top), and "isEmpty". Each stack element in a linked list implementation is represented as a node in the linked list. The head of the linked list serves as a representation of the top of the stack.

The following is a description of an algorithm to implement a stack using a linked list:

  • Define a class for the node of the linked list. Each node should contain the data (the item being added to the stack) and a pointer to the next node in the stack.
  • Define a class for the stack This class should contain a pointer to the top node of the stack.
  • Implement the push A new node containing the item to be added should be created during this operation, and its next pointer should be set to the stack's current top. After that, update the top pointer to the new node.
  • Implement the pop The data from the top node of the stack should be returned along with this action. To begin, make sure the stack is empty (i.e., if the top pointer is None). If it's not empty, set the top pointer to the next node in the stack and return the data of the removed node.
  • Implement the peek Without deleting the top node of the stack, this action should return its data. Simply return the node's data that the top pointer is pointing to do this.
  • Implement the is_empty This operation should return True if the stack is empty (i.e., if the top pointer is None) and False otherwise.

Complete implementation of a stack using a linked list in Python:

Node class:

It is a simple class that defines the structure of each node in the linked list. It has two instance variables: next and data, which represents the item being added to the stack, and a pointer to the next node in the stack. If a Node object is created without any arguments, the default value of data is None.

Stack class:

This class represents the stack itself. It has only one instance variable: top, which is a pointer to the top node of the stack. If the stack is empty, top is None.

The push method adds a new node to the top of the stack. It creates a new Node object with the given data and sets its next pointer to the current top of the stack. The top pointer is then updated to include the new node.

The pop method removes and returns the top item from the stack. It first checks if the stack is empty (i.e. if the top is None). If it's not empty, it saves the data of the current top node, updates the top to point to the next node in the stack, and returns the saved data.

Without deleting it, the peek method returns the data of the top item in the stack. It begins by making sure the stack is empty. If it's not empty, it returns the data attribute of the top node.

The is_empty method returns True if the stack is empty (i.e., if top is None) and False otherwise.

Some other additional points:

  • One of the advantages of implementing a stack using a linked list is that the size of the stack can be dynamic, meaning that it can grow or shrink as items are added or removed. Unlike an array implementation of a stack, a linked list implementation does not require a fixed size.
  • The push, pop, peek, and is_empty methods for a linked list implementation of a stack have a time complexity of O(1). It is because these operations only involve modifying the head node of the linked list, which takes constant time.

It's important to note that a linked list implementation of a stack in Python is not thread-safe, meaning that it's not safe to use in a multi-threaded environment. If multiple threads are accessing the same stack object and modifying it concurrently, it can result in unexpected behavior and data corruption. In a multi-threaded environment, it's recommended to use a thread-safe implementation of a stack.

Time Complexity:

The time complexity of the basic stack operations using a linked list implementation are:

Push: O(1)

Pop: O(1)

Peek: O(1)

Is Empty: O(1)

All these operations take constant time, regardless of the size of the stack. It is because we only need to modify the top node of the linked list to perform any of these operations.

Space Complexity:

The space complexity of a stack using a linked list in Python depends on the number of elements in the stack. Since each element in the stack is represented by a node in the linked list, the space required is proportional to the number of elements in the stack. We can conclude that the space complexity of a stack using a linked list in Python is O(n), where n is the number of elements in the stack.

It is to be noted that the space complexity of a linked list implementation of a stack is not affected by the maximum size of the stack, unlike an array implementation which would require a fixed amount of memory for the maximum size of the stack.