ये दोनों बहुत समान लगते हैं और इनमें लगभग समान संरचना होती है। क्या फर्क पड़ता है? प्रत्येक के अलग-अलग संचालन के लिए समय जटिलताएं क्या हैं?
ये दोनों बहुत समान लगते हैं और इनमें लगभग समान संरचना होती है। क्या फर्क पड़ता है? प्रत्येक के अलग-अलग संचालन के लिए समय जटिलताएं क्या हैं?
जवाबों:
हीप केवल इस बात की गारंटी देता है कि निचले स्तरों पर तत्वों की तुलना में उच्च स्तरों पर तत्व अधिक से अधिक (अधिकतम-ढेर के लिए) या छोटे (न्यूनतम-हीप के लिए) हैं, जबकि BST आदेश ("बाएं" से "दाएं") की गारंटी देता है। यदि आप सॉर्ट किए गए तत्व चाहते हैं, तो BST के साथ जाएं। डांटे द्वारा एक geek नहीं है
Heap, FindMin / findMax (O (1)) में बेहतर है, जबकि BST सभी ढूंढों में अच्छा है (O (logN))। डालें दोनों संरचनाओं के लिए O (logN) है। यदि आप केवल findMin / findMax (जैसे प्राथमिकता-संबंधी) की परवाह करते हैं, तो ढेर के साथ जाएं। यदि आप सब कुछ हल करना चाहते हैं, तो BST के साथ जाएं।
दोनों द्विआधारी खोज के पेड़ और द्विआधारी ढेर वृक्ष-आधारित डेटा संरचनाओं हैं।
हीप्स को अपने बच्चों पर प्राथमिकता देने के लिए नोड्स की आवश्यकता होती है। एक अधिकतम ढेर में, प्रत्येक नोड के बच्चों को खुद से कम होना चाहिए। यह मिन हीप के लिए विपरीत है:
बाइनरी सर्च ट्री (BST) सिबलिंग नोड्स के बीच एक विशिष्ट ऑर्डरिंग (प्री-ऑर्डर, इन-ऑर्डर, पोस्ट-ऑर्डर) का पालन करते हैं। पेड़ को ढेर के विपरीत हल करना चाहिए:
सम्मिलन, विलोपन और खोज के लिए BST का औसत ।
बाइनरी हैम्प्स में findMin / findMax और O ( log n ) के लिए औसत
सारांश
Type BST (*) Heap
Insert average log(n) 1
Insert worst log(n) log(n) or n (***)
Find any worst log(n) n
Find max worst 1 (**) 1
Create worst n log(n) n
Delete worst log(n) log(n)
इस तालिका में सभी औसत समय सम्मिलित करने के अलावा उनके सबसे खराब समय के समान हैं।
*
: इस उत्तर में हर जगह, BST == संतुलित BST, क्योंकि असंतुलित रूप से असमान रूप से चूसता है**
: इस उत्तर में समझाया गया एक मामूली संशोधन का उपयोग करना***
: log(n)
पॉइंटर ट्री हीप के लिए, n
डायनेमिक ऐरे हीप के लिएएक बीएसटी पर बाइनरी हीप के फायदे
बाइनरी हीप में औसत समय सम्मिलन O(1)
BST के लिए है O(log(n))
। यह ढेर की हत्यारा विशेषता है।
अन्य ढेर भी हैं जो फाइबोनैचि हीप कीO(1)
तरह परिशोधित (मजबूत) तक पहुंचते हैं , और सबसे खराब स्थिति, ब्रोडल कतार की तरह , हालांकि गैर-स्पर्शोन्मुख प्रदर्शन के कारण वे व्यावहारिक नहीं हो सकते हैं: https // / हैं फाइबोनैचि-ढेर या brodal-कतारों से इस्तेमाल में अभ्यास कहीं भी
बाइनरी हीप्स को डायनेमिक सरणियों या पॉइंटर-आधारित पेड़ों में से किसी एक पर लागू किया जा सकता है , BST केवल पॉइंटर-आधारित पेड़ हैं। तो ढेर के लिए हम अधिक स्थान कुशल सरणी कार्यान्वयन का चयन कर सकते हैं, अगर हम सामयिक आकार के अक्षांशों को वहन कर सकते हैं।
द्विआधारी ढेर निर्माण है O(n)
सबसे खराब स्थिति , O(n log(n))
BST के लिए।
बाइनरी हीप पर बीएसटी का लाभ
मनमाने तत्वों की खोज है O(log(n))
। यह बीएसटी की हत्यारा विशेषता है।
ढेर के लिए, यह O(n)
सामान्य रूप से है, सबसे बड़े तत्व को छोड़कर O(1)
।
BST पर ढेर का "गलत" फायदा
ढेर को O(1)
अधिकतम, BST ढूंढना है O(log(n))
।
यह एक सामान्य गलत धारणा है, क्योंकि सबसे बड़े तत्व का ट्रैक रखने के लिए एक BST को संशोधित करना तुच्छ है, और जब भी उस तत्व को बदला जा सकता है, तो इसे अपडेट करें: एक बड़ा एक स्वैप के सम्मिलन पर, हटाने पर दूसरा सबसे बड़ा लगता है। https://stackoverflow.com/questions/7878622/can-we-use-binary-search-tree-to-simulate-heap-operation ( Yeo द्वारा उल्लिखित )।
वास्तव में, यह BSTs की तुलना में ढेर की एक सीमा है: केवल सबसे बड़ी तत्व के लिए कुशल खोज है।
औसत बाइनरी हीप इन्सर्ट है O(1)
सूत्रों का कहना है:
सहज तर्क:
एक बाइनरी हीप में, किसी दिए गए इंडेक्स पर मूल्य बढ़ाना भी O(1)
उसी कारण से है। लेकिन अगर आप ऐसा करना चाहते हैं, तो यह संभावना है कि आप ढेर कार्यों पर एक अतिरिक्त सूचकांक अप-टू-डेट रखना चाहते हैं https://stackoverflow.com/questions/17009056/how-to-implement-ologn-decrease की-ऑपरेशन-फॉर-मिन-हीप-बेस्ड-प्रायोरिटी-क्वे जैसे उदा। बिना किसी अतिरिक्त लागत के संभव।
जीसीसी सी ++ मानक पुस्तकालय वास्तविक हार्डवेयर पर बेंचमार्क सम्मिलित करते हैं
मैंने C ++ std::set
( रेड-ब्लैक ट्री BST ) और std::priority_queue
( डायनेमिक ऐरे हीप ) को यह देखने के लिए डाला कि क्या मैं इन्सर्ट टाइम के बारे में सही था, और यही मुझे मिला:
तो स्पष्ट रूप से:
ढेर डालने का समय मूल रूप से स्थिर है।
हम स्पष्ट रूप से डायनामिक ऐरे रिसाइज पॉइंट्स देख सकते हैं। चूँकि हम हर 10k आवेषण पर औसत हैं , जो कि सिस्टम के ऊपर के शोर पर कुछ भी देखने में सक्षम हैं , वे चोटियाँ वास्तव में दिखाए गए की तुलना में लगभग 10k गुना बड़ी हैं!
ज़ूम किया गया ग्राफ़ अनिवार्य रूप से केवल सरणी आकार बिंदुओं को बाहर करता है, और दिखाता है कि लगभग सभी आवेषण 25 नैनोसेकंड के नीचे आते हैं।
BST लॉगरिदमिक है। सभी आवेषण औसत ढेर डालने की तुलना में बहुत धीमी हैं।
BST बनाम हैशमैप का विस्तृत विश्लेषण यहां: https://stackoverflow.com/questions/18414579/what-data-structure-is-inside-stdmap-in-c/51945119#5191911119
GCC C ++ मानक पुस्तकालय gem5 पर बेंचमार्क डालें
मणि 5 एक पूर्ण प्रणाली सिम्युलेटर है, और इसलिए इसके साथ एक असीम रूप से सटीक घड़ी प्रदान करता है m5 dumpstats
। इसलिए मैंने व्यक्तिगत आवेषण के लिए समय का अनुमान लगाने के लिए इसका उपयोग करने की कोशिश की।
व्याख्या:
ढेर अभी भी स्थिर है, लेकिन अब हम अधिक विस्तार से देखते हैं कि कुछ लाइनें हैं, और प्रत्येक उच्च रेखा अधिक विरल है।
यह उच्च और उच्च आवेषण के लिए स्मृति पहुँच विलंबता के अनुरूप होना चाहिए।
TODO मैं वास्तव में BST की पूरी तरह से व्याख्या नहीं कर सकता क्योंकि यह इतना लघुगणक और कुछ अधिक स्थिर नहीं दिखता है।
इस अधिक विस्तार के साथ, हालांकि हम देख सकते हैं कि कुछ अलग रेखाएँ भी देख सकते हैं, लेकिन मुझे यकीन नहीं है कि वे क्या प्रतिनिधित्व करते हैं: मैं नीचे की रेखा को पतले होने की उम्मीद करूंगा, क्योंकि हम शीर्ष नीचे सम्मिलित करते हैं?
अराजकता 64 HPI CPU पर इस Buildroot सेटअप के साथ बेंचमार्क ।
BST को किसी सरणी पर कुशलता से लागू नहीं किया जा सकता है
हीप संचालन को केवल एकल ट्री शाखा को ऊपर या नीचे करने की आवश्यकता होती है, इसलिए O(log(n))
सबसे खराब स्थिति स्वैप, O(1)
औसत।
BST को संतुलित रखने के लिए पेड़ के घुमाव की आवश्यकता होती है, जो एक और के लिए शीर्ष तत्व को बदल सकता है, और पूरे सरणी को चारों ओर ( O(n)
) में स्थानांतरित करने की आवश्यकता होगी ।
हीप्स को एक एरे पर कुशलता से लागू किया जा सकता है
वर्तमान सूचकांक से माता-पिता और बच्चों के अनुक्रमित की गणना की जा सकती है जैसा कि यहां दिखाया गया है ।
BST की तरह कोई भी संतुलन कार्य नहीं कर रहे हैं।
Delete min सबसे चिंताजनक ऑपरेशन है क्योंकि इसे टॉप डाउन करना है। लेकिन यह हमेशा यहां बताए अनुसार ढेर की एक शाखा "पेरोक्लेटिंग डाउन" द्वारा किया जा सकता है । यह ओ (लॉग (एन)) सबसे खराब स्थिति की ओर जाता है, क्योंकि ढेर हमेशा अच्छी तरह से संतुलित होता है।
यदि आप अपने द्वारा हटाए गए प्रत्येक के लिए एक नोड डाल रहे हैं, तो आप एसिम्प्टोटिक ओ (1) औसत डालने का लाभ खो देते हैं जो कि स्टेप्स हटाए जाने पर हावी होगा, और आप बीएसटी का भी उपयोग कर सकते हैं। दिज्क्स्त्र हालांकि प्रत्येक हटाने के लिए कई बार नोड्स अपडेट करता है, इसलिए हम ठीक हैं।
डायनेमिक ऐरे ढेर बनाम पॉइंटर ट्री ढेर
हैप्स को पॉइन्टरों के ढेर के ऊपर कुशलता से लागू किया जा सकता है: https://stackoverflow.com/questions/19720438/is-it-possible-to-make-efficient-pointer-based-binary-heap-implementations
गतिशील सरणी कार्यान्वयन अधिक स्थान कुशल है। मान लीजिए कि प्रत्येक ढेर तत्व में सिर्फ एक सूचक होता है struct
:
पेड़ के कार्यान्वयन को प्रत्येक तत्व के लिए तीन बिंदुओं को संचित करना चाहिए: माता-पिता, बाएं बच्चे और दाएं बच्चे। तो मेमोरी का उपयोग हमेशा होता है 4n
(3 ट्री पॉइंटर्स + 1struct
पॉइंटर)।
ट्री बीएसटी को और अधिक संतुलन जानकारी की आवश्यकता होगी, जैसे कि काले-लाल-नेस।
2n
दोहरीकरण के बाद डायनामिक एरे का कार्यान्वयन आकार का हो सकता है । तो औसतन यह होने जा रहा है 1.5n
।
दूसरी ओर, पेड़ के ढेर में सबसे खराब स्थिति सम्मिलित होती है, क्योंकि इसके आकार को दोगुना करने के लिए बैकिंग डायनामिक सरणी की नकल होती है O(n)
सबसे खराब स्थिति होती है, जबकि पेड़ का ढेर प्रत्येक नोड के लिए नए छोटे आवंटन करता है।
फिर भी, बैकिंग सरणी दोहरीकरण को O(1)
परिशोधन किया जाता है, इसलिए यह अधिकतम विलंबता पर विचार करने के लिए नीचे आता है। यहाँ उल्लेख किया ।
दर्शन
BST एक माता-पिता और सभी वंशजों के बीच एक वैश्विक संपत्ति बनाए रखते हैं (बाएं छोटे, दाएं बड़े)।
BST का शीर्ष नोड मध्य तत्व है, जिसे बनाए रखने के लिए वैश्विक ज्ञान की आवश्यकता होती है (यह जानकर कि कितने छोटे और बड़े तत्व हैं)।
यह वैश्विक संपत्ति बनाए रखने के लिए अधिक महंगा है (लॉग एन डालें), लेकिन अधिक शक्तिशाली खोज (लॉग एन खोज) देता है।
माता-पिता माता-पिता और प्रत्यक्ष बच्चों (माता-पिता> बच्चों) के बीच एक स्थानीय संपत्ति बनाए रखते हैं।
एक ढेर का शीर्ष नोट बड़ा तत्व है, जिसे केवल अपने माता-पिता को बनाए रखने के लिए स्थानीय ज्ञान की आवश्यकता होती है।
संदेह से जुड़ी सूची
एक दोगुनी लिंक की गई सूची को ढेर के सबसेट के रूप में देखा जा सकता है, जहां पहले आइटम की सबसे बड़ी प्राथमिकता होती है, तो आइए उनकी तुलना यहां भी करें:
O(1)
सबसे खराब स्थिति चूंकि हमारे पास आइटम के लिए संकेत हैं, और अपडेट वास्तव में सरल हैO(1)
औसत, इस प्रकार लिंक की गई सूची से भी बदतर। अधिक सामान्य सम्मिलन की स्थिति के लिए ट्रेडऑफ़।O(n)
दोनों के लिएइसके लिए एक उपयोग का मामला है जब ढेर की कुंजी वर्तमान टाइमस्टैम्प है: उस स्थिति में, नई प्रविष्टियां हमेशा सूची की शुरुआत में जाएंगी। इसलिए हम सटीक टाइमस्टैम्प को भी पूरी तरह से भूल सकते हैं, और सूची में स्थिति को प्राथमिकता के रूप में रख सकते हैं।
इसका उपयोग LRU कैश को लागू करने के लिए किया जा सकता है । वैसे ही जैसे डिज्कस्ट्रा की तरह ढेर अनुप्रयोगों के लिए , आप सूची की इसी नोड के लिए कुंजी से एक अतिरिक्त hashmap रखने के लिए है, जो नोड जल्दी से अद्यतन करने के लिए खोजने के लिए चाहते हैं।
विभिन्न बैलेंस्ड BST की तुलना
हालांकि एसिम्प्टोटिक सम्मिलित हैं और सभी डेटा संरचनाओं के लिए बार-बार मिलते हैं जिन्हें आमतौर पर "संतुलित BSTs" के रूप में वर्गीकृत किया जाता है जो मैंने अब तक एक ही देखा है, अलग-अलग BBST में अलग-अलग ट्रेड-ऑफ़ हैं। मैंने अभी तक इसका पूरी तरह से अध्ययन नहीं किया है, लेकिन इन ट्रेड-ऑफ को संक्षेप में प्रस्तुत करना अच्छा होगा:
यह सभी देखें
CS पर समान प्रश्न: बाइनरी सर्च ट्री और बाइनरी हीप में क्या अंतर है?
डेटा संरचना के साथ किसी को चिंता के स्तरों को अलग करना है।
सार डेटा संरचनाओं इस सवाल में (संग्रहीत वस्तुओं, अपने अभियान) अलग हैं। एक प्राथमिकता कतार को लागू करता है, दूसरा एक सेट। एक प्राथमिकता कतार एक मनमाना तत्व खोजने में दिलचस्पी नहीं रखती है, केवल सबसे बड़ी प्राथमिकता वाला।
संरचनाओं का ठोस कार्यान्वयन । हालांकि पहली नजर में दोनों अलग-अलग संरचनात्मक गुणों के साथ (बाइनरी) पेड़ हैं। चाबियों के संभावित क्रम और संभावित वैश्विक संरचना दोनों अलग-अलग हैं। (कुछ हद तक, एक BST
कुंजी में, बाएं से दाएं, एक हीप में उन्हें शीर्ष-नीचे ऑर्डर करने का आदेश दिया गया है।) चूंकि आईपीलेंट सही ढंग से टिप्पणी करता है कि एक ढेर भी "पूर्ण" होना चाहिए।
निम्न स्तर के कार्यान्वयन में अंतिम अंतर है । ए (असंतुलित) बाइनरी सर्च-ट्री में पॉइंटर्स का उपयोग करके एक मानक कार्यान्वयन है। इसके विपरीत एक बाइनरी हीप एक सरणी (सटीक रूप से प्रतिबंधित संरचना के कारण) का उपयोग करके एक कुशल कार्यान्वयन है।