Design a stack with operations on middle element (original) (raw)

Last Updated : 13 Apr, 2025

Design a stack data structure that supports the following four operations, each in constant time complexity, i.e., O(1):

**Examples:

**Input: operations =["push", "push", "findMiddle", "pop", "deleteMiddle"]
values = [[1], [2], [], [], []]
**Output: 2 1
**Explanation: Let's break down the sequence of operations more clearly:

  1. **First Operation: Push the value **1 onto the stack.
  2. **Second Operation: Push the value **2 onto the stack. At this point, the stack (from bottom to top) is: [1, 2].
  3. **Third Operation: Retrieve the middle element. Since the stack contains two items, the middle element is defined as ****2 (**second middle).
  4. **Fourth Operation: Pop the top element, which is **2, removing it from the stack.
  5. **Fifth Operation: Delete the middle element. With **2 already removed, only **1 remains; hence, **1 is also deleted.

Try It Yourselfredirect icon

Using Doubly Linked List - O(1) Time and O(n) Space

The important question is, whether to use a linked list or array for the implementation of the stack? Please note that we need to find and delete the middle element. Deleting an element from the middle is not O(1) for the array. Also, we may need to move the middle pointer up when we push an element and move down when we pop(). In a singly linked list, moving the middle pointer in both directions is not possible.

The idea is to use a doubly linked list (DLL) along with a pointer that specifically tracks the middle element. This design allows direct access to the middle element and makes it possible to update the pointer in constant time when performing operations like inserting, removing, or shifting elements in the list.

Below is given the step-by-step approach:

Below is given the **implementation:

C++ `

#include <bits/stdc++.h> using namespace std;

// Node Structure class Node { public: int data; Node *next; Node *prev; Node(int data) { this->data = data; next = nullptr; prev = nullptr; } };

// Stack strcutre class myStack { Node *head; Node *mid; int size;

public: myStack() { size = 0; head = nullptr; mid = nullptr; }

void push(int data) {

    Node *temp = new Node(data);
    if (size == 0) {
        head = temp;
        mid = temp;
        size++;
        return;
    }

    head->next = temp;
    temp->prev = head;

    // update the pointers
    head = head->next;
    if (size % 2 == 1)
    {
        mid = mid->next;
    }
    size++;
}

int pop() {
    int data = -1;
    if (size != 0) {
        Node *toPop = head;
        data = toPop->data;
        if (size == 1) {
            head = nullptr;
            mid = nullptr;
        }
        else {
            head = head->prev;
            head->next = nullptr;
            if (size % 2 == 0) {
                mid = mid->prev;
            }
        }
        delete toPop;
        size--;
    }
    return data;
}

int findMiddle() {
    if (size == 0) {
        return -1;
    }
    return mid->data;
}

void deleteMiddle() {
    if (size != 0) {
        Node *toDelete = mid;
        if (size == 1) {
            head = nullptr;
            mid = nullptr;
        }
        else if (size == 2) {
            head = head->prev;
            mid = mid->prev;
            head->next = nullptr;
        }
        else {
            mid->next->prev = mid->prev;
            mid->prev->next = mid->next;
            if (size % 2 == 0) {
                mid = mid->prev;
            }
            else {
                mid = mid->next;
            }
        }
        delete toDelete;
        size--;
    }
}

};

int main() { myStack st; st.push(1); st.push(2); cout << st.findMiddle() << " "; st.deleteMiddle(); cout << st.pop(); return 0; }

Java

import java.util.*;

class GfG {

// Node Structure
static class Node {
    
    int data;
    Node next;
    Node prev;
    
    Node(int data) {
        this.data = data;
        next = null;
        prev = null;
    }
}

// Stack strcutre
static class myStack {
    
    Node head;
    Node mid;
    int size;
    
    myStack() {
        size = 0;
        head = null;
        mid = null;
    }
    
    void push(int data) {
        
        Node temp = new Node(data);
        if (size == 0) {
            head = temp;
            mid = temp;
            size++;
            return;
        }
        
        head.next = temp;
        temp.prev = head;
        
        // update the pointers
        head = head.next;
        if (size % 2 == 1) {
            mid = mid.next;
        }
        size++;
    }
    
    int pop() {
        
        int data = -1;
        if (size != 0) {
            Node toPop = head;
            data = toPop.data;
            if (size == 1) {
                head = null;
                mid = null;
            }
            else {
                head = head.prev;
                head.next = null;
                if (size % 2 == 0) {
                    mid = mid.prev;
                }
            }
            size--;
        }
        return data;
    }
    
    int findMiddle() {
        
        if (size == 0) {
            return -1;
        }
        return mid.data;
    }
    
    void deleteMiddle() {
        
        if (size != 0) {
            Node toDelete = mid;
            if (size == 1) {
                head = null;
                mid = null;
            }
            else if (size == 2) {
                head = head.prev;
                mid = mid.prev;
                head.next = null;
            }
            else {
                toDelete.next.prev = toDelete.prev;
                toDelete.prev.next = toDelete.next;
                if (size % 2 == 0) {
                    mid = mid.prev;
                }
                else {
                    mid = mid.next;
                }
            }
            size--;
        }
    }
}

public static void main(String[] args) {
    myStack st = new myStack();
    st.push(1);
    st.push(2);
    System.out.print(st.findMiddle() + " ");
    st.deleteMiddle();
    System.out.print(st.pop());
}

}

Python

Node Structure

class Node:

def __init__(self, data):
    self.data = data
    self.next = None
    self.prev = None

Stack strcutre

class myStack:

def __init__(self):
    self.head = None
    self.mid = None
    self.size = 0

def push(self, data):
    
    temp = Node(data)
    if self.size == 0:
        self.head = temp
        self.mid = temp
        self.size += 1
        return
    
    self.head.next = temp
    temp.prev = self.head
    
    # update the pointers
    self.head = self.head.next
    if self.size % 2 == 1:
        self.mid = self.mid.next
    self.size += 1

def pop(self):
    
    data = -1
    if self.size != 0:
        toPop = self.head
        data = toPop.data
        if self.size == 1:
            self.head = None
            self.mid = None
        else:
            self.head = self.head.prev
            self.head.next = None
            if self.size % 2 == 0:
                self.mid = self.mid.prev
        self.size -= 1
    return data

def findMiddle(self):
    
    if self.size == 0:
        return -1
    return self.mid.data

def deleteMiddle(self):
    
    if self.size != 0:
        toDelete = self.mid
        if self.size == 1:
            self.head = None
            self.mid = None
        elif self.size == 2:
            self.head = self.head.prev
            self.mid = self.mid.prev
            self.head.next = None
        else:
            toDelete.next.prev = toDelete.prev
            toDelete.prev.next = toDelete.next
            if self.size % 2 == 0:
                self.mid = self.mid.prev
            else:
                self.mid = self.mid.next
        self.size -= 1

if name == "main": st = myStack() st.push(1) st.push(2) print(st.findMiddle(), end=" ") print(st.pop())

C#

using System;

class GfG {

// Node Structure
class Node {
    
    public int data;
    public Node next;
    public Node prev;
    
    public Node(int data) {
        this.data = data;
        next = null;
        prev = null;
    }
}

// Stack strcutre
class myStack {
    
    Node head;
    Node mid;
    int size;
    
    public myStack() {
        size = 0;
        head = null;
        mid = null;
    }
    
    public void push(int data) {
        
        Node temp = new Node(data);
        if (size == 0) {
            head = temp;
            mid = temp;
            size++;
            return;
        }
        
        head.next = temp;
        temp.prev = head;
        
        // update the pointers
        head = head.next;
        if (size % 2 == 1) {
            mid = mid.next;
        }
        size++;
    }
    
    public int pop() {
        
        int data = -1;
        if (size != 0) {
            Node toPop = head;
            data = toPop.data;
            if (size == 1) {
                head = null;
                mid = null;
            }
            else {
                head = head.prev;
                head.next = null;
                if (size % 2 == 0) {
                    mid = mid.prev;
                }
            }
            size--;
        }
        return data;
    }
    
    public int findMiddle() {
        
        if (size == 0) {
            return -1;
        }
        return mid.data;
    }
    
    public void deleteMiddle() {
        
        if (size != 0) {
            Node toDelete = mid;
            if (size == 1) {
                head = null;
                mid = null;
            }
            else if (size == 2) {
                head = head.prev;
                mid = mid.prev;
                head.next = null;
            }
            else {
                toDelete.next.prev = toDelete.prev;
                toDelete.prev.next = toDelete.next;
                if (size % 2 == 0) {
                    mid = mid.prev;
                }
                else {
                    mid = mid.next;
                }
            }
            size--;
        }
    }
}

public static void Main() {
    myStack st = new myStack();
    st.push(1);
    st.push(2);
    Console.Write(st.findMiddle() + " ");
    st.deleteMiddle();
    Console.Write(st.pop());
}

}

JavaScript

class MyStack { constructor() { this.stack = []; this.queue = []; }

push(data) {
    this.queue.push(data);
    while (this.queue.length > this.stack.length + 1) {
        this.stack.push(this.queue.shift());
    }
}

pop() {
    if (this.queue.length === 0) {
        while (this.stack.length > 1) {
            this.queue.push(this.stack.pop());
        }
        return this.stack.pop();
    }
    return this.queue.pop();
}

findMiddle() {
    if (this.queue.length > 0) {
        return this.queue[0];
    } else if (this.stack.length > 0) {
        return this.stack[Math.floor((this.stack.length - 1) / 2)];
    }
    return -1;
}

deleteMiddle() {
    if (this.queue.length > 0) {
        this.queue.shift();
    } else if (this.stack.length > 0) {
        const midIndex = Math.floor((this.stack.length - 1) / 2);
        this.stack.splice(midIndex, 1);
    }
}

}

// Example usage: const s = new MyStack(); s.push(1); s.push(2); console.log(s.findMiddle()); // Expected output: 1 s.deleteMiddle(); console.log(s.pop()); // Expected output: 2

`

Using Stack and Doubly Ended Queue - O(1) Time and O(n) Space

The idea is to split the data between two structures: a standard stack and a deque. The stack stores the older half of the elements, while the deque holds the newer half. By keeping the deque's size equal to or one more than the stack, the middle element always remains at the front of the deque. This enables us to delete or access the middle element in constant time.

Below is given the step-by-step approach:

Consider Operations on My_stack:

Operation stack deque

add(2) { } {2}

add(5) {2} {5}

add(3) {2} {5,3}

add(7) {2,5} {3,7}

add(4) {2,5} {3,7,4}

deleteMiddle() {2,5} {7,4}

deleteMiddle() {2} {5,4}

pop() {2} {5}

pop() { } {2}

deleteMiddle() { } { }

Below is given the **implementation:

C++ `

#include <bits/stdc++.h> using namespace std;

class myStack { stack s; deque dq;

public: void push(int data) { dq.push_back(data); if (dq.size() > s.size() + 1) { int temp = dq.front(); dq.pop_front(); s.push(temp); } }

int pop() {
    int data = dq.back();
    dq.pop_back();
    if (s.size() > dq.size()) {
        int temp = s.top();
        s.pop();
        dq.push_front(temp);
    }
    return data;
}

int findMiddle() { 
    return dq.front(); 
}

void deleteMiddle() {
    dq.pop_front();
    if (s.size() > dq.size()) {
        int temp = s.top();
        s.pop();
        dq.push_front(temp);
    }
}

};

int main() { myStack s; s.push(1); s.push(2); cout << s.findMiddle() << " "; s.deleteMiddle(); cout << s.pop(); return 0; }

Java

import java.util.*;

class GfG {

static class myStack {
    Stack<Integer> s = new Stack<>();
    Deque<Integer> dq = new ArrayDeque<>();

    void push(int data) {
        dq.addLast(data);
        if (dq.size() > s.size() + 1) {
            int temp = dq.removeFirst();
            s.push(temp);
        }
    }

    int pop() {
        int data = dq.removeLast();
        if (s.size() > dq.size()) {
            int temp = s.pop();
            dq.addFirst(temp);
        }
        return data;
    }

    int findMiddle() {
        return dq.peekFirst();
    }

    void deleteMiddle() {
        dq.removeFirst();
        if (s.size() > dq.size()) {
            int temp = s.pop();
            dq.addFirst(temp);
        }
    }
}

public static void main(String[] args) {
    myStack s = new myStack();
    s.push(1);
    s.push(2);
    System.out.print(s.findMiddle() + " ");
    s.deleteMiddle();
    System.out.print(s.pop());
}

}

Python

from collections import deque

class myStack:

def __init__(self):
    self.s = []
    self.dq = deque()

def push(self, data):
    self.dq.append(data)
    if len(self.dq) > len(self.s) + 1:
        temp = self.dq.popleft()
        self.s.append(temp)

def pop(self):
    data = self.dq.pop()
    if len(self.s) > len(self.dq):
        temp = self.s.pop()
        self.dq.appendleft(temp)
    return data

def findMiddle(self):
    return self.dq[0]

def deleteMiddle(self):
    self.dq.popleft()
    if len(self.s) > len(self.dq):
        temp = self.s.pop()
        self.dq.appendleft(temp)

s = myStack() s.push(1) s.push(2) print(s.findMiddle(), end=" ") s.deleteMiddle() print(s.pop())

C#

using System; using System.Collections.Generic;

class GfG {

class myStack {
    Stack<int> s = new Stack<int>();
    LinkedList<int> dq = new LinkedList<int>();

    public void push(int data) {
        dq.AddLast(data);
        if (dq.Count > s.Count + 1) {
            int temp = dq.First.Value;
            dq.RemoveFirst();
            s.Push(temp);
        }
    }

    public int pop() {
        int data = dq.Last.Value;
        dq.RemoveLast();
        if (s.Count > dq.Count) {
            int temp = s.Pop();
            dq.AddFirst(temp);
        }
        return data;
    }

    public int findMiddle() {
        return dq.First.Value;
    }

    public void deleteMiddle() {
        dq.RemoveFirst();
        if (s.Count > dq.Count) {
            int temp = s.Pop();
            dq.AddFirst(temp);
        }
    }
}

public static void Main() {
    myStack s = new myStack();
    s.push(1);
    s.push(2);
    Console.Write(s.findMiddle() + " ");
    s.deleteMiddle();
    Console.Write(s.pop());
}

}

JavaScript

class myStack { constructor() { this.s = []; this.dq = []; }

push(data) {
    this.dq.push(data);
    if (this.dq.length > this.s.length + 1) {
        let temp = this.dq.shift();
        this.s.push(temp);
    }
}

pop() {
    let data = this.dq.pop();
    if (this.s.length > this.dq.length) {
        let temp = this.s.pop();
        this.dq.unshift(temp);
    }
    return data;
}

findMiddle() {
    return this.dq[0];
}

deleteMiddle() {
    this.dq.shift();
    if (this.s.length > this.dq.length) {
        let temp = this.s.pop();
        this.dq.unshift(temp);
    }
}

}

let s = new myStack(); s.push(1); s.push(2); process.stdout.write(s.findMiddle() + " "); s.deleteMiddle(); process.stdout.write(s.pop().toString());

`