Queues, Deques & Priority Queues (Intro)

Queue, Deque ও Priority Queue

Read: ~35 min Intermediate 7 practice problems Live code runner

1. FIFO — First In, First Out

A queue is the opposite of a stack: the first one in is the first one out. Operations: enqueue / push at the back, dequeue / pop at the front, front() peek. Queues power BFS, schedulers, message buses, print spoolers — anything where order of arrival matters.

Queue হলো লাইনে দাঁড়ানো মানুষের সাথে মিল — যিনি প্রথমে এসেছেন, তিনিই প্রথমে সেবা পাবেন। BFS, OS scheduler, printer queue, message bus — সব জায়গায় queue।
10 20 30 40 50 FRONT (dequeue) REAR (enqueue) Figure 10.1 — A queue. Items enter from the rear (right) and leave from the front (left).

2. Circular Queue Over a Fixed Array

A naive linear queue wastes space — once you dequeue from the front, the empty slot is gone. A circular queue wraps the rear pointer back around using (rear + 1) % capacity, so all slots stay usable.

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

struct CQ {
    vector<int> a;
    int front, rear, sz, cap;
    CQ(int n) : a(n), front(0), rear(-1), sz(0), cap(n) {}
    bool push(int x) {
        if (sz == cap) return false;
        rear = (rear + 1) % cap;
        a[rear] = x; sz++;
        return true;
    }
    bool pop() {
        if (sz == 0) return false;
        front = (front + 1) % cap; sz--;
        return true;
    }
    int peek() { return a[front]; }
};

int main() {
    CQ q(4);
    q.push(10); q.push(20); q.push(30); q.push(40);
    cout << "front=" << q.peek() << "\n";
    q.pop(); q.pop();
    q.push(50); q.push(60);   // wraps around
    cout << "after wrap, front=" << q.peek() << ", size=" << q.sz;
}

3. Deque — Push and Pop at Both Ends

A deque (double-ended queue) is a queue that supports O(1) operations at both ends. std::deque<T> in C++ is the standard implementation. The killer use is the sliding-window maximum in O(n).

Sliding-window max trick Keep a deque of indices in the current window such that values are in decreasing order. The front of the deque is always the max of the window.
উইন্ডোতে decreasing order-এ index রাখুন — front-ই উত্তর।
sliding_max.cpp
#include <bits/stdc++.h>
using namespace std;

vector<int> windowMax(vector<int>& a, int k) {
    deque<int> dq;     // stores indices, decreasing values
    vector<int> ans;
    for (int i = 0; i < (int)a.size(); i++) {
        while (!dq.empty() && dq.front() <= i - k) dq.pop_front();
        while (!dq.empty() && a[dq.back()] < a[i]) dq.pop_back();
        dq.push_back(i);
        if (i >= k - 1) ans.push_back(a[dq.front()]);
    }
    return ans;
}

int main() {
    vector<int> a = {1,3,-1,-3,5,3,6,7};
    for (int x : windowMax(a, 3)) cout << x << " ";
}

Each index is pushed and popped at most once → O(n) total.

4. Priority Queue — A Quick Preview

A priority queue is a queue where highest priority (max or min) comes out first, not just FIFO. The standard implementation is a binary heap (Module 15). std::priority_queue<T> is a max-heap by default.

Priority queue-এ পরিচয় শুধু এখানে — বিস্তারিত আসছে Module 15 (Heaps & Heapsort)-এ। আপাতত মনে রাখুন: insert এবং extract-top — দুটিই O(log n)।

Queue / Deque

  • FIFO order or both-ends
  • O(1) for all operations
  • Used in: BFS, sliding window, scheduling

Priority Queue

  • Highest-priority first
  • O(log n) push / pop, O(1) top
  • Used in: Dijkstra, Huffman, top-K problems

5. Practice Problems

  1. Implement a queue using two stacks (amortised O(1)).
    দুটি stack দিয়ে queue বানান (amortised O(1))।
    ✨ Show Answer (উত্তর দেখুন)
    a1.cpp
    #include <bits/stdc++.h>
    using namespace std;
    struct QQ {
        stack<int> in, out;
        void push(int x) { in.push(x); }
        int  pop() {
            if (out.empty())
                while (!in.empty()) { out.push(in.top()); in.pop(); }
            int v = out.top(); out.pop(); return v;
        }
    };
    int main() {
        QQ q;
        for (int x : {1,2,3}) q.push(x);
        cout << q.pop() << " " << q.pop() << " " << q.pop();
    }
  2. Print the first negative integer in every window of size k.
    প্রতিটি size-k window-এ প্রথম negative integer প্রিন্ট করুন।
    ✨ Show Answer (উত্তর দেখুন)
    a2.cpp
    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        vector<int> a = {12,-1,-7,8,-15,30,16,28};
        int k = 3;
        deque<int> dq;
        for (int i = 0; i < (int)a.size(); i++) {
            if (a[i] < 0) dq.push_back(i);
            while (!dq.empty() && dq.front() <= i - k) dq.pop_front();
            if (i >= k - 1) cout << (dq.empty() ? 0 : a[dq.front()]) << " ";
        }
    }
  3. Rotten oranges (BFS). Given a grid of fresh (1) and rotten (2) oranges, return the minutes until all rot.
    Rotten oranges সমস্যা — BFS দিয়ে।
    ✨ Show Answer (উত্তর দেখুন)
    a3.cpp
    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        vector<vector<int>> g = {{2,1,1},{1,1,0},{0,1,1}};
        int R = g.size(), C = g[0].size(), fresh = 0, t = 0;
        queue<pair<int,int>> q;
        for (int i=0; i<R; i++) for (int j=0; j<C; j++) {
            if (g[i][j]==2) q.push({i,j});
            if (g[i][j]==1) fresh++;
        }
        int dx[]={-1,1,0,0}, dy[]={0,0,-1,1};
        while (!q.empty() && fresh) {
            int sz = q.size();
            while (sz--) {
                auto [x,y] = q.front(); q.pop();
                for (int d=0; d<4; d++) {
                    int nx=x+dx[d], ny=y+dy[d];
                    if (nx>=0&&nx<R&&ny>=0&&ny<C&&g[nx][ny]==1) {
                        g[nx][ny]=2; fresh--; q.push({nx,ny});
                    }
                }
            }
            t++;
        }
        cout << (fresh ? -1 : t);
    }
  4. Use a min-priority-queue to merge k sorted arrays into one.
    Min-PQ দিয়ে k সর্টেড অ্যারে merge করুন।
    ✨ Show Answer (উত্তর দেখুন)
    a4.cpp
    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        vector<vector<int>> arrs = {{1,5,9},{2,6},{3,4,10}};
        priority_queue<tuple<int,int,int>, vector<tuple<int,int,int>>, greater<>> pq;
        for (int i=0; i<(int)arrs.size(); i++) if (!arrs[i].empty()) pq.push({arrs[i][0], i, 0});
        while (!pq.empty()) {
            auto [v, i, j] = pq.top(); pq.pop();
            cout << v << " ";
            if (j+1 < (int)arrs[i].size()) pq.push({arrs[i][j+1], i, j+1});
        }
    }
  5. Reorganize a string so no two adjacent characters are the same (use a max-PQ on counts).
    পাশাপাশি একই char না হয় — string reorganize করুন।
    ✨ Show Answer (উত্তর দেখুন)
    a5.cpp
    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        string s = "aaabbc";
        int cnt[26] = {};
        for (char c : s) cnt[c-'a']++;
        priority_queue<pair<int,char>> pq;
        for (int i=0; i<26; i++) if (cnt[i]) pq.push({cnt[i], 'a'+i});
        string out;
        while (pq.size() >= 2) {
            auto [c1, ch1] = pq.top(); pq.pop();
            auto [c2, ch2] = pq.top(); pq.pop();
            out += ch1; out += ch2;
            if (--c1) pq.push({c1, ch1});
            if (--c2) pq.push({c2, ch2});
        }
        if (!pq.empty()) {
            if (pq.top().first > 1) { cout << "impossible"; return 0; }
            out += pq.top().second;
        }
        cout << out;
    }
  6. Implement a stack using two queues (amortised).
    দুটি queue দিয়ে stack বানান।
    ✨ Show Answer (উত্তর দেখুন)
    a6.cpp
    #include <bits/stdc++.h>
    using namespace std;
    struct SS {
        queue<int> q;
        void push(int x) {
            q.push(x);
            int sz = q.size();
            while (--sz) { q.push(q.front()); q.pop(); }
        }
        int pop() { int v = q.front(); q.pop(); return v; }
    };
    int main() {
        SS s;
        for (int x : {1,2,3}) s.push(x);
        cout << s.pop() << " " << s.pop() << " " << s.pop();
    }
  7. Find the top-k frequent integers using a min-heap of size k.
    size-k min-heap দিয়ে top-k frequent integer বের করুন।
    ✨ Show Answer (উত্তর দেখুন)
    a7.cpp
    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        vector<int> a = {1,1,1,2,2,3,4,4,4,4};
        int k = 2;
        unordered_map<int,int> cnt;
        for (int x : a) cnt[x]++;
        priority_queue<pair<int,int>, vector<pair<int,int>>, greater<>> pq;
        for (auto& [v, c] : cnt) {
            pq.push({c, v});
            if ((int)pq.size() > k) pq.pop();
        }
        while (!pq.empty()) { cout << pq.top().second << " "; pq.pop(); }
    }

Summary — Module 10

FIFO queues, double-ended deques, and priority queues round out the linear toolbox. BFS needs a queue. Sliding-window max needs a deque. Dijkstra needs a priority queue. Phase 2 is complete — next we sort and search.

Queue, deque, priority queue — তিনটিই ছোট কিন্তু শক্তিশালী। BFS, sliding window, Dijkstra — সবই এদের উপর দাঁড়িয়ে। Phase 2 শেষ।

Next Module → Linear & Binary Search — Phase 3 শুরু।