मुझे स्टैक के ऊपर Deque का उपयोग क्यों करना चाहिए?


157

मुझे Stackअपने उपयोग के मामले के लिए एक डेटा संरचना की आवश्यकता है । मुझे डेटा संरचना में आइटम पुश करने में सक्षम होना चाहिए और मैं केवल स्टैक से अंतिम आइटम को पुनर्प्राप्त करना चाहता हूं। ढेर के लिए JavaDoc का कहना है:

LIFO स्टैक ऑपरेशंस का एक अधिक पूर्ण और सुसंगत सेट, Deque इंटरफ़ेस और इसके कार्यान्वयन द्वारा प्रदान किया जाता है, जिसका उपयोग इस वर्ग के लिए किया जाना चाहिए। उदाहरण के लिए:

Deque<Integer> stack = new ArrayDeque<>();

मैं निश्चित रूप से यहाँ सिंक्रनाइज़ व्यवहार नहीं करना चाहता क्योंकि मैं इस डेटास्ट्रक्चर को स्थानीय तरीके से उपयोग कर रहा हूँ। इसके अलावा मैं क्यों पसंद किए जाने वाले Dequeअधिक Stackयहाँ?

पुनश्च: जेकादॉक डेके कहते हैं:

डेक्स को LIFO (लास्ट-इन-फर्स्ट-आउट) स्टैक के रूप में भी इस्तेमाल किया जा सकता है। इस इंटरफ़ेस को विरासत स्टैक वर्ग के लिए प्राथमिकता में उपयोग किया जाना चाहिए।


1
यह अधिक बेक्ड-इन विधियाँ प्रदान करता है, या बल्कि "अधिक पूर्ण और सुसंगत सेट" है, जो आपके द्वारा लाभ उठाने पर आपको लिखने के लिए कोड की मात्रा को कम कर देगा?

जवाबों:


190

एक बात के लिए, यह विरासत के संदर्भ में अधिक समझदार है। तथ्य यह है कि Stackफैली हुई है Vectorमेरे विचार में वास्तव में अजीब है। जावा में आरंभिक विरासत में IMO का अत्यधिक उपयोग किया गया था -Properties एक और उदाहरण।

मेरे लिए, आपके द्वारा उद्धृत डॉक्स में महत्वपूर्ण शब्द सुसंगत हैDequeउन सभी प्रचालनों के एक समूह को उजागर करता है, जो किसी संग्रह के आरंभ या अंत से आइटम्स को लाने / जोड़ने / हटाने में सक्षम होने के बारे में है - और यह वह है। किसी तत्व को स्थिति से जानबूझकर एक्सेस करने का कोई तरीका नहीं है, जो Stackउजागर करता है क्योंकि यह एक उपवर्ग है Vector

ओह, और Stackइसका कोई इंटरफ़ेस भी नहीं है, इसलिए यदि आप जानते हैं कि आपको ज़रूरत हैStack ऑपरेशनों की है जो आपको एक विशिष्ट ठोस वर्ग के लिए प्रतिबद्ध हैं, जो आमतौर पर एक अच्छा विचार नहीं है।

जैसा कि टिप्पणियों में बताया गया है, Stackऔर Dequeइसके पुनरावृत्ति आदेश हैं:

Stack<Integer> stack = new Stack<>();
stack.push(1);
stack.push(2);
stack.push(3);
System.out.println(new ArrayList<>(stack)); // prints 1, 2, 3


Deque<Integer> deque = new ArrayDeque<>();
deque.push(1);
deque.push(2);
deque.push(3);
System.out.println(new ArrayList<>(deque)); // prints 3, 2, 1

जिसे Deque.iterator () के लिए JavaDocs में भी समझाया गया है :

इस क्रम में तत्वों पर उचित क्रम में एक पुनरावृत्ति देता है। तत्वों को पहले (सिर) से अंतिम (पूंछ) के क्रम में वापस किया जाएगा।


10
ArrayDeque के javadoc का कहना है कि "यह वर्ग स्टैक की तुलना में अधिक तेज़ होने की संभावना है, जब एक स्टैक के रूप में उपयोग किया जाता है, और जब कतार के रूप में उपयोग किया जाता है तो लिंक्डलिस्ट की तुलना में तेज़ होता है।" .. मैं यह कैसे निर्दिष्ट करूं कि क्या मैं इसे एक स्टैक के रूप में या एक कतार के रूप में उपयोग करना चाहता हूं?
गीक

23
@ गीक: आप नहीं। मुद्दा यह है कि यदि आप कतारबद्ध व्यवहार चाहते हैं, तो आप उपयोग कर सकते हैं LinkedList, लेकिन ArrayDequeue(अक्सर) तेज होगा। यदि आप स्टैक व्यवहार चाहते हैं, तो आप उपयोग कर सकते हैं, Stackलेकिन ArrayDeque(अक्सर) तेज होगा।
जॉन स्कीट ने

7
हालांकि यह अमूर्तता के मामले में कम समझदार नहीं है? मेरा मतलब है, न तो समाधान अमूर्त के संदर्भ में वास्तव में अच्छा है, क्योंकि Stackप्रतिनिधि एक्सपोज़र की समस्या है, लेकिन अगर मुझे एक स्टैक डेटा संरचना चाहिए तो मैं पुश, पॉप और झांकना जैसी विधियों को कॉल करने में सक्षम होना चाहूंगा, और न कि चीजों को स्टैक के दूसरे छोर के साथ करते हैं।
पेटीपप्रो

4
@JonSkeet भी स्टैक का इटेरेटर गलत है, क्योंकि यह ऊपर से नीचे की बजाय नीचे से ऊपर की ओर होता है। stackoverflow.com/questions/16992758/…
Pavel

1
@PeteyPabPro: आप सही हैं। स्टैक के रूप में डीकेयू का उपयोग करना अभी भी स्टैक के विरासत वाले वेक्टर तरीकों के रूप में गैर-एलआईएफओ उपयोग की अनुमति देता है। समस्या की एक व्याख्या और एक समाधान ( एनकैप्सुलेशन के
rics

4

यहाँ स्टैक वर्ग के वर्णन में वर्णित विसंगति की मेरी व्याख्या है।

यदि आप सामान्य प्रयोजन के कार्यान्वयन को देखते हैं - आप देखेंगे कि सेट, मानचित्र और सूची के कार्यान्वयन के लिए एक सुसंगत दृष्टिकोण है।

  • सेट और मैप के लिए हमारे पास हैश मैप और पेड़ों के साथ 2 मानक कार्यान्वयन हैं। पहले एक का सबसे अधिक उपयोग किया जाता है और दूसरे का उपयोग तब किया जाता है जब हमें एक आदेशित संरचना की आवश्यकता होती है (और यह अपने स्वयं के इंटरफ़ेस को भी लागू करता है - SortedSet या SortedMap)।

  • हम यहां घोषित Set<String> set = new HashSet<String>();कारणों की तरह घोषित करने की पसंदीदा शैली का उपयोग कर सकते हैं

लेकिन स्टैक वर्ग: 1) का अपना इंटरफ़ेस नहीं है; 2) वेक्टर क्लास का एक उपवर्ग है - जो आकार बदलने योग्य सरणी पर आधारित है; तो स्टैक की सूची कार्यान्वयन कहां से जुड़ा हुआ है?

Deque इंटरफ़ेस में हमें दो कार्यान्वयन (रिज़र्व करने योग्य सरणी - ArrayDeque; लिंक्ड सूची - लिंक्डलिस्ट) सहित ऐसी समस्याएं नहीं हैं।


2

स्टैक के ऊपर Dequeue का उपयोग करने का एक और कारण Dequeue में LIFO अवधारणा को लागू करने के साथ स्ट्रीम में कनवर्ट करने वाली स्ट्रीम का उपयोग करने की क्षमता है, जबकि Stack नहीं करता है।

Stack<Integer> stack = new Stack<>();
Deque<Integer> deque = new ArrayDeque<>();

stack.push(1);//1 is the top
deque.push(1)//1 is the top
stack.push(2);//2 is the top
deque.push(2);//2 is the top

List<Integer> list1 = stack.stream().collect(Collectors.toList());//[1,2]

List<Integer> list2 = deque.stream().collect(Collectors.toList());//[2,1]

2

यहां कुछ कारण बताए गए हैं कि स्टैक की तुलना में डेक्स बेहतर क्यों है:

ऑब्जेक्ट ओरिएंटेड डिज़ाइन - इनहेरिटेंस, एब्सट्रैक्शन, क्लासेस और इंटरफेस: स्टैक एक क्लास है, डीके एक इंटरफेस है। केवल एक वर्ग को बढ़ाया जा सकता है, जबकि किसी भी संख्या के इंटरफेस को जावा में एकल वर्ग (कई प्रकार की विरासत) द्वारा लागू किया जा सकता है। डीकेई इंटरफेस का उपयोग करना कंक्रीट स्टैक वर्ग और उसके पूर्वजों पर निर्भरता को हटाता है और आपको अधिक लचीलापन देता है, जैसे कि एक अलग वर्ग का विस्तार करने की स्वतंत्रता या डीके के अलग-अलग कार्यान्वयन (जैसे लिंक्डलिस्ट, एरेडेक) को स्वैप करना।

असंगति: स्टैक वेक्टर क्लास का विस्तार करता है, जो आपको सूचकांक द्वारा तत्व तक पहुंचने की अनुमति देता है। यह एक स्टैक वास्तव में क्या करना चाहिए के साथ असंगत है, यही कारण है कि डेक्स इंटरफ़ेस को प्राथमिकता दी जाती है (यह इस तरह के संचालन की अनुमति नहीं देता है) - इसका अनुमत संचालन एक एफआईएफओ या एलआईएफओ डेटा संरचना की अनुमति के अनुरूप है।

प्रदर्शन: स्टैक का विस्तार करने वाला वेक्टर वर्ग मूल रूप से एक ArrayList का "थ्रेड-सेफ" संस्करण है। सिंक्रोनाइज़ेशन संभावित रूप से आपके अनुप्रयोग के लिए महत्वपूर्ण प्रदर्शन हिट हो सकता है। इसके अलावा, अनावश्यक कार्यक्षमता के साथ अन्य वर्गों का विस्तार (# 2 में वर्णित) अपनी वस्तुओं को प्रस्फुटित करें, संभवतः अतिरिक्त मेमोरी और प्रदर्शन ओवरहेड की बहुत अधिक लागत।


-1

मेरे लिए यह विशिष्ट बिंदु गायब था: स्टैक थ्रेडसेफ़ है क्योंकि यह वेक्टर से लिया गया है, जबकि सबसे अधिक डेक्स कार्यान्वयन नहीं हैं, और इस तरह से तेजी से अगर आप केवल एक ही धागे में इसका उपयोग करते हैं।


grep "इसके अलावा"
पेसरियर

-1

प्रदर्शन एक कारण हो सकता है। एक एल्गोरिथ्म जिसका मैंने इस्तेमाल किया था वह 7.6 मिनट से 1.5 मिनट तक केवल स्टैक को डेक्स से बदलकर नीचे चला गया।


grep "इसके अलावा"
पेसरियर

-6

Deque का उपयोग उस स्थिति में किया जाता है, जब आप सिर और पूंछ दोनों से तत्वों को पुनः प्राप्त करना चाहते हैं। यदि आप एक साधारण स्टैक चाहते हैं, तो एक छल के लिए जाने की आवश्यकता नहीं है।


1
कृपया प्रश्न में अंतिम पैराग्राफ देखें। जावेदॉक का कहना है कि डेक्स का इस्तेमाल किया जाना चाहिए और मैं जानना चाहता था कि क्यों?
गीक

2
Deque को प्राथमिकता दी जाती है क्योंकि आप बीच में तत्वों तक नहीं पहुँच सकते। यह डबल समाप्त हो गया है, इसलिए फीफो के लिए फिलो हो सकता है।
तुफिर

मुझे लगता है कि वे जो कहना चाहते हैं वह यह है कि वर्ग स्टैक संचालन का स्पष्ट तरीकों के रूप में समर्थन करता है। इसके दस्तावेज और तरीके देखें। इसमें स्टैक को लागू करने के लिए स्पष्ट समर्थन है।
अभिषेक नंदगाँवकर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.