Open In App

Design Front Middle Back Queue using STL

Design a data structure that supports the following operations in queue efficiently:

Examples:



Operations Queue Return
push__front(4) 4 _
push__back(2) 4, 2 _
push__middle(1) 4, 1, 2 _
pop_front() 1, 2 4
pop__middle() 2 1
pop__front() _ 2
pop__front() _ -1

Deque-based Approach: The problem can be solved using two deque. The idea is to use two deques. Operation at the back of the queue is to be done at the end of the second deque, and operation at the middle is to be done at the end of the first deque. Follow the steps below to solve the problem:

Below is the implementation of the above approach:






// C++ program to implement
// the above approach
 
#include <bits/stdc++.h>
using namespace std;
 
// Create class Queue.
class Queue {
 
    // Initialize two deques
    deque<int> first, second;
 
    // Function to balance the size of
    // first ans second deque
    void equalizeSizedeque1deque2()
    {
 
        // If size of less than second
        if (first.size() <= second.size())
            return;
 
        // Insert the last element of
        // first deque into second deque
        second.push_front(first.back());
 
        // Pop the front element
        // of the deque
        first.pop_back();
    }
 
    // Function to balance the size of
    // second and first deque
    void equalizeSizedeque2deque1()
    {
 
        // if size of second deque deceed
        // the first deque by 1
        if (second.size() <= first.size() + 1)
            return;
 
        // Insert front element of second
        // deque into the first
        first.push_back(second.front());
 
        // Remove front element of
        // second deque
        second.pop_front();
    }
 
public:
    // Function to insert element
    // at front of queue
    void push__front(int val)
    {
 
        // Insert val into first deque
        first.push_front(val);
 
        // Balancing the size of second
        equalizeSizedeque1deque2();
    }
 
    // Function to insert val
    // into the middle of queue
    void push__middle(int val)
    {
 
        // Insert val into first deque
        first.push_back(val);
 
        // Balancing the size of
        // second deque
        equalizeSizedeque1deque2();
    }
 
    // Function to insert val
    // into back of queue
    void push__back(int val)
    {
 
        // Insert val into second deque
        second.push_back(val);
 
        // Balancing the size of
        // second deque
        equalizeSizedeque2deque1();
    }
 
    // Function to pop front
    // element from queue
    int pop__front()
    {
 
        // If first deque and second
        // deque is empty
        if (first.empty() && second.empty())
            return -1;
 
        int ans;
 
        // If the first deque
        // is empty
        if (first.empty()) {
 
            // Stores front element
            // of second deque
            ans = second.front();
 
            // Pop front element of
            // second deque
            second.pop_front();
        }
        else {
 
            // Stores front element
            // of first deque
            ans = first.front();
 
            // Pop front element of
            // first deque
            first.pop_front();
 
            // Balancing the size of first
            equalizeSizedeque2deque1();
        }
        return ans;
    }
 
    // Function to pop middle
    // element of queue
    int pop__middle()
    {
 
        // If both deques are empty
        if (first.empty() && second.empty())
            return -1;
 
        // Stores mid element
        // of queue
        int ans;
 
        // If size of both deque is equal
        if (first.size() == second.size()) {
 
            // Stores back element
            // of first deque
            ans = first.back();
 
            // Pop back element of
            // first deque
            first.pop_back();
        }
        else {
 
            // Stores front element
            // of second deque
            ans = second.front();
 
            // Pop front element
            // from second deque
            second.pop_front();
        }
        return ans;
    }
 
    // Function to remove mid
    // element from queue
    int pop__back()
    {
 
        // If both the deque are empty
        if (first.empty() && second.empty())
            return -1;
 
        // Stores back element from
        // second deque
        int ans = second.back();
 
        // Pop back element from
        // second deque
        second.pop_back();
 
        // Balancing the size of second
        equalizeSizedeque1deque2();
        return ans;
    }
};
 
// Driver code
int main()
{
    Queue q;
    q.push__front(1);
    q.push__back(2);
    q.push__middle(3);
    cout << q.pop__middle() << " ";
    cout << q.pop__back() << " ";
    cout << q.pop__front() << " ";
    return 0;
}

Output: 
3 2 1

 

Time Complexity Analysis:

push__front(x) pop__front() push__back(x) pop__back() push__middle(x) pop__middle()
O(1) O(1) O(1) O(1) O(1) O(1)

List-based Approach: Follow the steps below to solve the problem:

Below is the implementation of the above approach:




// C++ program to implement
// the above approach
 
#include <bits/stdc++.h>
using namespace std;
 
// Create structure of queue
class Queue {
 
    list<int> l;
 
public:
    // Function to push element
    // at front of the queue
    void push__front(int val)
    {
        l.push_front(val);
    }
 
    // Function to push element
    // at middle of the queue
    void push__middle(int val)
    {
 
        auto itr = l.begin();
 
        // Traverse the list
        advance(itr, l.size() / 2);
 
        // Insert element into
        // middle of the list
        l.insert(itr, val);
    }
 
    // Function to insert element
    // at the back of the queue
    void push__back(int val)
    {
        l.push_back(val);
    }
 
    // Function to pop element from
    // front of the queue
    int pop__front()
    {
 
        // Stores front element
        // of queue
        int val = -1;
        if (l.size()) {
            val = l.front();
            l.pop_front();
        }
        return val;
    }
 
    // Function to pop middle element
    // of the queue
    int pop__middle()
    {
        int val = -1;
        if (l.size()) {
            auto itr = l.begin();
 
            // Traverse the list
            advance(itr, (l.size() - 1) / 2);
            val = *itr;
 
            // Remove mid element
            // from queue
            l.erase(itr);
        }
        return val;
    }
 
    // Function to pop end
    // element of the queue
    int pop__back()
    {
 
        // Stores back element
        // of the queue
        int val = -1;
 
        if (l.size()) {
            val = l.back();
            l.pop_back();
        }
        return val;
    }
};
 
// Drivers code
int main()
{
    Queue q;
    q.push__front(1);
    q.push__back(2);
    q.push__middle(3);
    cout << q.pop__middle() << " ";
    cout << q.pop__back() << " ";
    cout << q.pop__front() << " ";
    return 0;
}

Output: 
3 2 1 

 

Time Complexity Analysis:

push__front(x) pop__front() push__back(x) pop__back() push__middle(x) pop__middle()
O(1) O(1) O(1) O(1) O(N) O(N)

Doubly linked list-based Approach: The problem can also be solved using a doubly-linked list without using STL by storing the address of the head and last node. Follow the steps below to solve the problem:


Article Tags :