स्टैक (Stacks)
LIFO — सबसे नया अंदर, सबसे नया बाहर
Stack · LIFO
init
Mini-game · balanced brackets (powered by a stack)
Type an expression. Brackets must open and close in mirror order
— ({[…]}) is fine, ([)] is not. The parser uses
a stack: every opener pushes the expected closer; every
closer must match the value on top. Watch how each character
is classified, and how the stack grows and shrinks below.
- opener → push
- closer matches top
- mismatch / underflow
- ignored char
खुद आज़माएँ: टोकनों को टॉवर पर push कीजिए; फिर pop कर हटाइए। उसके नीचे: कोई भी कोष्ठक (bracket) वाली स्ट्रिंग parens गेम में डालिए — स्टैक ही उसका पार्सर है।
यह क्यों मायने रखता है
स्टैक हर जगह हैं: फ़ंक्शन कॉल, undo/redo, अभिव्यक्ति (expression) पार्सिंग, backtracking एल्गोरिथ्म। स्टैक को समझना यानी यह समझना कि प्रोग्राम कैसे चलते हैं और उन समस्याओं को कैसे हल किया जाए जिनमें कुछ 'याद रखना' और 'वापस लौटाना' ज़रूरी होता है।
मूल विचार
किसी कैफ़ेटेरिया में रखी प्लेटों की ढेरी को सोचिए। आप सिर्फ़ ऊपर से ही जोड़ या हटा सकते हैं। सबसे आख़िर में रखी प्लेट सबसे पहले उठती है।
सबसे बाद में अंदर, सबसे पहले बाहर (Last In, First Out — LIFO)।
यह सीधी-सी पाबंदी ग़ज़ब की ताक़तवर है:
- फ़ंक्शन कॉल: जब फ़ंक्शन A, B को बुलाता है, तो B का संदर्भ ऊपर चढ़ जाता है। जब B लौटता है, वह pop हो जाता है, और A आगे बढ़ता है।
- Undo: हर क्रिया स्टैक पर push होती है। Undo आख़िरी क्रिया को pop कर देता है।
- कोष्ठक मिलान: '(' देखकर push कीजिए, ')' देखकर pop। अगर संतुलित है, तो अंत में स्टैक ख़ाली रहेगा।
सारे ऑपरेशन O(1) हैं — आप कभी सिर्फ़ ऊपरी सिरे को ही छूते हैं।
मुख्य बातें
- push, pop, और peek — सभी O(1) हैं
- LIFO क्रम — सबसे बाद में अंदर, सबसे पहले बाहर
- फ़ंक्शन कॉल स्टैक, अभिव्यक्ति मूल्यांकन, backtracking में इस्तेमाल
- ऐरे या लिंक्ड लिस्ट किसी से भी बन सकता है
और गहराई में
कॉल स्टैक ही वह वजह है जिससे रिकर्सिव फ़ंक्शन काम करते हैं — हर कॉल के स्थानीय चर (local variables) स्टैक पर push होते हैं और लौटने पर pop हो जाते हैं। जब रिकर्शन बहुत गहरा चला जाता है तो स्टैक ओवरफ़्लो होता है। स्टैक infix से postfix संकेतन में बदलने (shunting-yard एल्गोरिथ्म) और postfix अभिव्यक्तियों को एक ही पास में हल करने की भी कुंजी हैं।
असल दुनिया में
- CPU कॉल स्टैक। आपका प्रोग्राम जो भी फ़ंक्शन कॉल करता है, हर एक एक स्टैक फ़्रेम push करता है (return address + locals + सहेजे गए registers)। हार्डवेयर का स्टैक पॉइंटर हर आधुनिक CPU पर एक register होता है। जब आप किसी स्टैक ट्रेस के साथ crash करते हैं, तो दरअसल आप स्टैक को ऊपर से नीचे तक पढ़ रहे होते हैं।
- ब्राउज़र undo/redo। दो स्टैक: एक बीती क्रियाओं के लिए, एक redo के लिए। हर एडिटर (Photoshop, VS Code, Figma) इसी पैटर्न पर बना है।
- स्पष्ट स्टैक से DFS। रिकर्शन स्टैक का परोक्ष इस्तेमाल है; गहरे ग्राफ़ों पर आप कॉल स्टैक उड़ने से बचने के लिए एक स्पष्ट स्टैक ऐरे रखते हैं। देखिए ग्राफ़ वाला पाठ — उसकी DFS सीमा (frontier) एक स्टैक ही है।
- रोबोटिक्स में रिकवरी स्थिति। किसी जोखिम भरी क्रिया से पहले पिछली "सुरक्षित" स्थिति को push करना, और नाकामी पर उसी पर वापस pop करना — गति-नियोजकों (motion planners) में
try/exceptशैली की रिकवरी की बुनियाद यही है। - कंपाइलर। हर पार्सर एक स्टैक इस्तेमाल करता है: shift/reduce पार्सिंग, अभिव्यक्ति पार्सिंग, scope ट्रैकिंग। नेस्टेड संरचना की स्टैक-संचालित पहचान से आपका कोड एक AST बन जाता है।
गणितीय ब्यौरा
- Time Complexity
Push: O(1)Pop: O(1)Peek: O(1)Search: O(n)- Space
- n तत्वों के लिए O(n)
क्रियान्वयन (Implementation)
स्टैक ऑपरेशन
let mut stack = Vec::new();
stack.push(1); // Push onto top
stack.push(2);
stack.push(3); // Stack: [1, 2, 3] (3 is top)
let top = stack.pop(); // Returns Some(3)
let peek = stack.last(); // Returns Some(&2)
चिर-परिचित उपयोग
- संतुलित कोष्ठक जाँच
- फ़ंक्शन कॉल स्टैक
- undo/redo सुविधा
- अभिव्यक्ति मूल्यांकन
- DFS traversal
अभ्यास
तीन चिर-परिचित स्टैक सवाल — हर एक LIFO अनुशासन को इस्तेमाल करने का अलग तरीक़ा है:
- Min Stack — आसान · एक समानांतर सहायक स्टैक चलते हुए न्यूनतम को ट्रैक करता है ताकि
getMinO(1) रहे - Next Greater Element — मध्यम · "इंतज़ार करते" इंडेक्सों का monotonic स्टैक, amortized O(n)
- Evaluate Postfix Expression — मध्यम · स्टैक एक कंप्यूटर की तरह; हर RPN कैलकुलेटर और JVM bytecode VM अभिव्यक्तियों को इसी तरह हल करता है