पाठ · #4 / 11

क़तार (Queues)

FIFO — हर बार न्यायसंगत क्रम

Queue · FIFO

head
tail
init

खुद आज़माएँ: बेल्ट पर enqueue/dequeue कीजिए। ring buffer पर स्विच करके देखिए कि कैसे सर्कुलर इंडेक्सिंग तय मेमोरी को दोबारा इस्तेमाल करती है — कभी कोई खिसकाव नहीं।

यह क्यों मायने रखता है

क़तारें प्रतीक्षा-पंक्तियों, कार्य-शेड्यूलिंग और breadth-first खोज को मॉडल करती हैं। जहाँ भी पहुँचने का क्रम मायने रखता हो, वहाँ आपको एक क़तार चाहिए। ये ऑपरेटिंग सिस्टम, नेटवर्किंग और ग्राफ़ एल्गोरिथ्म की बुनियाद हैं।

मूल विचार

किसी कॉफ़ी शॉप की पंक्ति को सोचिए। पंक्ति में सबसे पहले खड़े व्यक्ति को सबसे पहले सेवा मिलती है। नए ग्राहक पीछे से जुड़ते हैं।

सबसे पहले अंदर, सबसे पहले बाहर (First In, First Out — FIFO)।

जहाँ स्टैक undo और backtracking के बारे में हैं, वहीं क़तारें निष्पक्षता और क्रम के बारे में हैं:

Enqueue (पीछे जोड़ना) और dequeue (आगे से हटाना), दोनों O(1) हैं।

मुख्य बातें

और गहराई में

दो-सिरों वाली क़तारें (deques) दोनों सिरों पर डालने/हटाने की छूट देती हैं — sliding-window एल्गोरिथ्म और "हर k आकार की विंडो में अधिकतम" को कुल O(n) में निकालने वाली monotonic-deque तरकीब के लिए उपयोगी। प्राथमिकता क़तारें (priority queues, हीप वाले पाठ में) "अन्यायपूर्ण" क़तारें हैं जहाँ महत्व पहुँचने के क्रम पर भारी पड़ता है — इस पाठ में बस एक घुंडी और घुमा दीजिए, और आपको एक हीप मिल जाती है। सर्कुलर बफ़र तय-आकार के ऐरे में लपेटकर (wrap around) क़तारों को कुशलता से लागू करते हैं।

असल दुनिया में

ring buffer O(1) amortized क्यों है — हालाँकि आकार-परिवर्तन O(n) है

एक भोली ऐरे-आधारित क़तार आगे से dequeue करते समय बाक़ी बचे सारे n तत्वों को बाएँ खिसका देती है — O(n)। ring buffer उन modular इंडेक्सों से इससे बच निकलता है जो आपने डेमो में देखे: front और rear क्षमता के modulo में आगे बढ़ते हैं, जिससे भरने को कोई अंतराल नहीं बचता।

पर जब ring भर जाता है तब क्या होता है? आप दुगुने आकार का नया बफ़र बनाकर कॉपी करते हैं। वह O(n) है — वही आकार-परिवर्तन तरकीब जो ऐरे दुगुना करने का प्रमाण इस्तेमाल करता है। n enqueue पर कुल काम 2n − 1 होता है, इसलिए प्रति-ऑपरेशन यह O(1) amortized है। दुगुना किए बिना — मान लीजिए आप हर बार एक स्थिर मात्रा से बढ़ते — तो कुल काम फूलकर O(n²) हो जाता।

यह दूसरी बार है जब आपने दुगुना करने का पैटर्न देखा है; आप इसे फिर देखेंगे हैश-टेबल rehashing में, और परोक्ष रूप से हीप निर्माण में। आकार पहचानिए: "कभी-कभार होने वाला महँगा ऑपरेशन, जिसकी क़ीमत पहले के कई सस्तों ने चुका दी" — यही एक वाक्य में amortized विश्लेषण है।

गणितीय ब्यौरा

Time Complexity
Enqueue: O(1)
Dequeue: O(1)
Peek front: O(1)
Search: O(n)
Circular Buffer
front = (front + 1) mod capacity
rear = (rear + 1) mod capacity

क्रियान्वयन (Implementation)

VecDeque से क़तार

use std::collections::VecDeque;

let mut queue = VecDeque::new();

queue.push_back(1);  // Enqueue
queue.push_back(2);
queue.push_back(3);  // Queue: [1, 2, 3]

let front = queue.pop_front();  // Returns Some(1)
// Queue is now [2, 3]

चिर-परिचित उपयोग

अभ्यास

तीन क़तार सवाल, हर एक FIFO अनुशासन के अलग पहलू पर टिका है:

सभी अभ्यास सवाल देखें