Implement Multi Stack (K stacks) using only one Data Structure


A dynamic multi-stack is a remarkable data structure that possesses the capacity to store elements in numerous stacks, with an ever-changing quantity of stacks. It can be a daunting task to implement K stacks utilizing only one data structure. In this instructional guide, we shall investigate two distinct techniques to execute dynamic multi-stack (K stacks) using C++. The initial technique employs an array to stock the elements, along with two additional arrays to monitor the topmost and following indices of the stacks. The secondary technique employs a vector of nodes to stock the elements, along with a vector to keep track of the head of every stack.

This article will center upon how we may execute dynamic multi-stack employing one data structure in C++.

Approaches

  • Approach 1 − Using an array to store the elements of the data structure and two auxiliary arrays to store the top element of each stack and the next index of the free slot in the array.

  • Approach 2 − Using a doubly linked list to store the elements of the data structure and a vector to store the head node of each stack.

Syntax

The given syntax is the declaration of a class named KStacks in C++. The class has the following member functions or methods −

  • A constructor method KStacks which takes two parameters k and n.

  • A method named push which takes two parameters item and sn and is used to insert an element into stack sn.

  • A method named pop which takes a single parameter sn and is used to remove an element from stack sn.

  • A method named is_empty which takes a single parameter sn and returns a boolean value indicating whether stack sn is empty or not.

  • A method named is_full which returns a boolean value indicating whether the entire data structure is full or not.

class KStacks {
   public:
   KStacks(int k, int n); // Constructor
   void push(int item, int sn); // Insert an element into stack 'sn'
   int pop(int sn); // Remove an element from stack 'sn'
   bool is_empty(int sn); // Check if stack 'sn' is empty
   bool is_full(); // Check if the entire data structure is full
};

Algorithm

The following is an algorithm to implement a K-stack dynamic multipack using a single data structure −

  • Step 1 − Start by creating a data structure that contains an array of size n to store the elements, along with two auxiliary arrays of size k. One array will store the information about the topmost element of each stack, while the other array will keep track of the next available index in the main array.

  • Step 2 − Next, we call the parent array and its corresponding array using the values -1 and 0.

  • Step 3 − Using the cart() function, we can add an object to a specific stack. This function requires two inputs: the item to be added and the group number. Before adding an item, the push() function checks if the data structure is full by comparing the next available index value with n. If there is still space, the item is added to the next available index and the value of the next available index is updated.

  • Step 4 − The pop() function is used to remove items from a particular stack, with the group number as its parameter. The pop() function checks if the stack is empty by comparing the parent array value with -1. If the stack is not empty, the pop() function removes the topmost element from the stack and updates the parent array value to point to the new topmost element.

  • Step 5 − To check if a specific stack is empty, we use the is_empty() function with the group number as its parameter. This function checks if the parent array value is equal to -1.

  • Step 6 − To check if all the stacks are full, we use the is_full() function, which checks if the next available index value is equal to n.

Approach 1

We shall adopt an approach that involves utilizing an array to reserve the elements, as well as two additional arrays to monitor the topmost and subsequent indices of the stacks. Although it is a straightforward and effective solution, it necessitates the predefinition of a predetermined number of stacks.

Below is the program code for the same.

Example

The code represents the implementation of the K Stacks data structure, which is a dynamic interpretation of the stack data structure, allowing for multiple stacks to be housed within a single array.

The KStacks class comprises three member variables −

  • arr − An array serving as storage for the elements of all stacks.

  • top − An array serving as storage for the top of each stack.

  • next − An array serving as storage for the next available position in the array.

  • push − To insert an element into a specified stack.

  • pop − To remove an element from a specified stack.

  • is_empty − To verify if a specified stack is empty.

  • is_full − To verify if the array is completely occupied.

In the main function, an instance of the KStacks class is generated, with the number of stacks and size of the array as input parameters. Then, elements are pushed into three distinct stacks. Lastly, the top elements from each stack are removed and displayed.

#include <iostream>
#include <vector>
#include<climits>
using namespace std;

class KStacks {
   private:
   int *arr;
   int *top;
   int *next;
   int n, k;
   public:
   KStacks(int k, int n) {
      this->k = k;
      this->n = n;
      arr = new int[n];
      top = new int[k];
      next = new int[n];
   for (int i = 0; i < k; i++)
      top[i] = -1;

   for (int i = 0; i < n - 1; i++)
      next[i] = i + 1;
   next[n - 1] = -1;
}

void push(int item, int sn) {
   if (is_full()) {
      cout << "Stack Overflow\n";
      return;
   }

   int i = next[sn];
   next[sn] = top[sn];
   top[sn] = i;
   arr[i] = item;
}

int pop(int sn) {
   if (is_empty(sn)) {
      cout << "Stack Underflow\n";
      return INT_MAX;
   }

   int i = top[sn];
   top[sn] = next[i];
   next[i] = i;
   return arr[i];
   }

   bool is_empty(int sn) {
      return top[sn] == -1;
   }

   bool is_full() {
      return next[0] == -1;
   }
};

int main() {
   KStacks ks(3, 10);
   ks.push(15, 2);
   ks.push(45, 2);

   ks.push(17, 1);
   ks.push(49, 1);
   ks.push(39, 1);

   ks.push(11, 0);
   ks.push(9, 0);
   ks.push(7, 0);

   cout << "Popped element from stack 2: " << ks.pop(2) << endl;
   cout << "Popped element from stack 1: " << ks.pop(1) << endl;
   cout << "Popped element from stack 0: " << ks.pop(0) << endl;

   return 0;
}

Output

Stack Overflow
Stack Overflow
Popped element from stack 2: Stack Underflow
2147483647
Popped element from stack 1: 39
Popped element from stack 0: 11

Approach 2

We shall adopt an approach wherein a vector of nodes shall be employed to store the elements. This approach shall be complemented by a vector that serves to maintain the head of each stack. Our approach proves to be a more pliant solution that can accommodate a variable number of stacks that undergo dynamic changes. However, this approach may impose a heavier memory burden and entail more overhead costs.

Example-2

The code constitutes a C++ program that realizes a data architecture referred to as "KStacks". This data structure enables the storage of multiple stacks within a single array through the application of a method known as "fixed division".

The "KStacks" class encompasses a range of member functions including "push", "pop", "is_empty", and "is_full". The "push" operation permits the addition of an item to a designated stack, while the "pop" function eradicates the top item from a designated stack.

The "is_empty" function returns true if the specified stack is unoccupied, and the "is_full" function returns true if all stacks are completely occupied. In the main function, three stacks with a capacity of 10 are established, and items are pushed and popped from each of the three stacks. Ultimately, the popped items are displayed on the console.

Code

#include <iostream>
#include <vector>
#include<climits>
using namespace std;

class Node {
public:
   int data;
   int prev;
   int next;
};

class KStacks {
  private:
   vector<Node> arr;
   vector<int> head;
   int n, k;
   int free;

  public:
   KStacks(int k, int n) {
   this->k = k;
   this->n = n;
   arr.resize(n);
   head.resize(k, -1);
   free = 0;
   for (int i = 0; i < n - 1; i++)
      arr[i].next = i + 1;
   arr[n - 1].next = -1;
}

void push(int item, int sn) {
   if (is_full()) {
      cout << "Stack Overflow\n";
      return;
   }

   int i = free;
   free = arr[i].next;
   arr[i].data = item;
   arr[i].prev = head[sn];
   arr[i].next = -1;

   if (head[sn] != -1)
      arr[head[sn]].next = i;
      head[sn] = i;
   }

   int pop(int sn) {
      if (is_empty(sn)) {
         cout << "Stack Underflow\n";
         return INT_MAX;
      }
      int i = head[sn];
      head[sn] = arr[i].prev;

      if (head[sn] != -1)
         arr[head[sn]].next = -1;

      arr[i].next = free;
      free = i;

      return arr[i].data;
   }

   bool is_empty(int sn) {
      return head[sn] == -1;
   }
   bool is_full() {
      return free == -1;
   }
};

int main() {
   KStacks ks(3, 10);
   ks.push(15, 2);
   ks.push(45, 2);

   ks.push(17, 1);
   ks.push(49, 1);
   ks.push(39, 1);

   ks.push(11, 0);
   ks.push(9, 0);
   ks.push(7, 0);

   cout << "Popped element from stack 2: " << ks.pop(2) <<endl;
   cout << "Popped element from stack 1: " << ks.pop(1) <<endl;
   cout << "Popped element from stack 0: " << ks.pop(0) <<endl;

   return 0;
}

Output

Popped element from stack 2: 45
Popped element from stack 1: 39
Popped element from stack 0: 7

Conclusion

In this article, we have discussed two different ways to create a dynamic multi-stack using a single data structure in C++. Both approaches have their advantages and disadvantages, and the choice of which one to use will depend on the specific needs of the problem at hand.

Updated on: 21-Jul-2023

1K+ Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements