बाइनरी सर्च ट्री और बाइनरी हीप में क्या अंतर है?


91

ये दोनों बहुत समान लगते हैं और इनमें लगभग समान संरचना होती है। क्या फर्क पड़ता है? प्रत्येक के अलग-अलग संचालन के लिए समय जटिलताएं क्या हैं?

जवाबों:


63

हीप केवल इस बात की गारंटी देता है कि निचले स्तरों पर तत्वों की तुलना में उच्च स्तरों पर तत्व अधिक से अधिक (अधिकतम-ढेर के लिए) या छोटे (न्यूनतम-हीप के लिए) हैं, जबकि BST आदेश ("बाएं" से "दाएं") की गारंटी देता है। यदि आप सॉर्ट किए गए तत्व चाहते हैं, तो BST के साथ जाएं। डांटे द्वारा एक geek नहीं है

Heap, FindMin / findMax (O (1)) में बेहतर है, जबकि BST सभी ढूंढों में अच्छा है (O (logN))। डालें दोनों संरचनाओं के लिए O (logN) है। यदि आप केवल findMin / findMax (जैसे प्राथमिकता-संबंधी) की परवाह करते हैं, तो ढेर के साथ जाएं। यदि आप सब कुछ हल करना चाहते हैं, तो BST के साथ जाएं।

xysun द्वारा


मुझे लगता है कि BST FindMin और findMax stackoverflow.com/a/27074221/764592
Yeo

10
मुझे लगता है कि यह सिर्फ एक गलत धारणा है। एक बाइनरी ट्री को मिनिमम और मैक्स को खोजने के लिए आसानी से संशोधित किया जा सकता है। यह वास्तव में ढेर का प्रतिबंध है: केवल कुशल खोज न्यूनतम या अधिकतम है। ढेर का सच्चा लाभ हे (1) औसत सम्मिलित है जैसा कि मैं समझाता हूं: stackoverflow.com/a/29548834/895245
Ciro Santilli 新疆 h h h 事件 '20

इस वीडियो के अनुसार , आपके निचले स्तर पर बड़े मूल्य हो सकते हैं, जब तक कि बड़ा निचले स्तर का वंशज न हो।
जिनन

हीप को जड़ से पत्ती की तरह छांटा जाता है और बीएसटी को दाएं से बाएं सॉर्ट किया जाता है।
दीप जोशी

34

दोनों द्विआधारी खोज के पेड़ और द्विआधारी ढेर वृक्ष-आधारित डेटा संरचनाओं हैं।

हीप्स को अपने बच्चों पर प्राथमिकता देने के लिए नोड्स की आवश्यकता होती है। एक अधिकतम ढेर में, प्रत्येक नोड के बच्चों को खुद से कम होना चाहिए। यह मिन हीप के लिए विपरीत है:

बाइनरी मैक्स हीप

बाइनरी सर्च ट्री (BST) सिबलिंग नोड्स के बीच एक विशिष्ट ऑर्डरिंग (प्री-ऑर्डर, इन-ऑर्डर, पोस्ट-ऑर्डर) का पालन करते हैं। पेड़ को ढेर के विपरीत हल करना चाहिए:

बाइनरी सर्च ट्री

सम्मिलन, विलोपन और खोज के लिए BST का औसत हे(लॉग इन करेंn)
बाइनरी हैम्प्स में findMin / findMax और O ( log n ) के लिए औसत हे(1)हे(लॉग इन करेंn)


1
@FrankW निष्कर्षण , नहीं? हे(लॉग इन करेंn)
flow2k

32

सारांश

          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(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)

सूत्रों का कहना है:

सहज तर्क:

  • नीचे के पेड़ के स्तर में शीर्ष स्तर की तुलना में अधिक तत्व होते हैं, इसलिए नए तत्वों को तल पर जाना लगभग निश्चित है
  • हीप सम्मिलन नीचे से शुरू होता है , BST शीर्ष से शुरू होना चाहिए

एक बाइनरी हीप में, किसी दिए गए इंडेक्स पर मूल्य बढ़ाना भी O(1)उसी कारण से है। लेकिन अगर आप ऐसा करना चाहते हैं, तो यह संभावना है कि आप ढेर कार्यों पर एक अतिरिक्त सूचकांक अप-टू-डेट रखना चाहते हैं https://stackoverflow.com/questions/17009056/how-to-implement-ologn-decrease की-ऑपरेशन-फॉर-मिन-हीप-बेस्ड-प्रायोरिटी-क्वे जैसे उदा। बिना किसी अतिरिक्त लागत के संभव।

जीसीसी सी ++ मानक पुस्तकालय वास्तविक हार्डवेयर पर बेंचमार्क सम्मिलित करते हैं

मैंने C ++ std::set( रेड-ब्लैक ट्री BST ) और std::priority_queue( डायनेमिक ऐरे हीप ) को यह देखने के लिए डाला कि क्या मैं इन्सर्ट टाइम के बारे में सही था, और यही मुझे मिला:

यहाँ छवि विवरण दर्ज करें

  • बेंचमार्क कोड
  • प्लॉट स्क्रिप्ट
  • प्लॉट डेटा
  • Ubuntu 19.04, GCC 8.3.0 पर लेनोवो थिंकपैड P51 लैपटॉप में CPU के साथ परीक्षण किया गया: Intel Core i7-7820HQ CPU (4 कोर / 8 धागे, 2.90 GHz आधार, 8 MB कैश), RAM: 2x सैमसंग M472A2K43BB1-CRC (2x 16GiB) , 2400 एमबीपीएस), एसएसडी: सैमसंग MZVLB512HAJQ-000L7 (512GB, 3,000 MB / s)

तो स्पष्ट रूप से:

  • ढेर डालने का समय मूल रूप से स्थिर है।

    हम स्पष्ट रूप से डायनामिक ऐरे रिसाइज पॉइंट्स देख सकते हैं। चूँकि हम हर 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 में अलग-अलग ट्रेड-ऑफ़ हैं। मैंने अभी तक इसका पूरी तरह से अध्ययन नहीं किया है, लेकिन इन ट्रेड-ऑफ को संक्षेप में प्रस्तुत करना अच्छा होगा:

  • लाल-काला पेड़ । 2019 तक सबसे अधिक इस्तेमाल किया जाने वाला BBST है, उदाहरण के लिए, यह GCC 8.3.0 C ++ कार्यान्वयन द्वारा उपयोग किया जाता है
  • एवीएल पेड़ । बीएसटी की तुलना में थोड़ा अधिक संतुलित होने की अपील करता है, इसलिए थोड़ी अधिक महंगी लागतों की कीमत पर विलंबता का पता लगाना बेहतर हो सकता है। विकी संक्षेप में बताता है: "AVL के पेड़ों की तुलना अक्सर लाल-काले पेड़ों से की जाती है क्योंकि दोनों ही समान संचालन के सेट का समर्थन करते हैं और बुनियादी कार्यों के लिए [समान] समय लेते हैं। लुक-सघन अनुप्रयोगों के लिए, AVL पेड़ लाल-काले पेड़ों की तुलना में तेज़ होते हैं क्योंकि वे अधिक सख्ती से संतुलित होते हैं। लाल-काले पेड़ों के समान, एवीएल पेड़ ऊंचाई-संतुलित होते हैं। दोनों सामान्य तौर पर, किसी भी म्यू <1/2 के लिए न तो वजन-संतुलित और न ही म्यू-संतुलित होते हैं, अर्थात, सहोदर नोड्स बेहद हो सकते हैं। वंशजों की अलग-अलग संख्या। "
  • WAVLमूल कागज पुनर्संतुलन और रोटेशन कार्यों पर सीमा के मामले में उस संस्करण के फायदे का उल्लेख है।

यह सभी देखें

CS पर समान प्रश्न: बाइनरी सर्च ट्री और बाइनरी हीप में क्या अंतर है?


1
बहुत बढ़िया जवाब। ढेर के सामान्य अनुप्रयोग माध्यिका, के मिन, शीर्ष कश्मीर तत्व हैं। इन सबसे सामान्य ऑपरेशन के लिए मिनट निकालें, फिर सम्मिलित करें (आमतौर पर हमारे पास कुछ शुद्ध डालने के संचालन के साथ छोटे ढेर होते हैं)। तो व्यवहार में ऐसा लगता है, इन एल्गोरिदम के लिए यह BST को बेहतर नहीं बनाता है।
युरा

1
असाधारण जवाब !!! अंतर्निहित हीप संरचना के रूप में डेक्स का उपयोग करके, आप नाटकीय रूप से आकार को कम कर सकते हैं, हालांकि यह अभी भी ओ (एन) सबसे खराब स्थिति है क्योंकि इसे चोक करने के लिए पॉइंटर्स के वास्तविक (छोटे) सरणी की आवश्यकता है।
बुलट

13

डेटा संरचना के साथ किसी को चिंता के स्तरों को अलग करना है।

  1. सार डेटा संरचनाओं इस सवाल में (संग्रहीत वस्तुओं, अपने अभियान) अलग हैं। एक प्राथमिकता कतार को लागू करता है, दूसरा एक सेट। एक प्राथमिकता कतार एक मनमाना तत्व खोजने में दिलचस्पी नहीं रखती है, केवल सबसे बड़ी प्राथमिकता वाला।

  2. संरचनाओं का ठोस कार्यान्वयन । हालांकि पहली नजर में दोनों अलग-अलग संरचनात्मक गुणों के साथ (बाइनरी) पेड़ हैं। चाबियों के संभावित क्रम और संभावित वैश्विक संरचना दोनों अलग-अलग हैं। (कुछ हद तक, एक BSTकुंजी में, बाएं से दाएं, एक हीप में उन्हें शीर्ष-नीचे ऑर्डर करने का आदेश दिया गया है।) चूंकि आईपीलेंट सही ढंग से टिप्पणी करता है कि एक ढेर भी "पूर्ण" होना चाहिए।

  3. निम्न स्तर के कार्यान्वयन में अंतिम अंतर है । ए (असंतुलित) बाइनरी सर्च-ट्री में पॉइंटर्स का उपयोग करके एक मानक कार्यान्वयन है। इसके विपरीत एक बाइनरी हीप एक सरणी (सटीक रूप से प्रतिबंधित संरचना के कारण) का उपयोग करके एक कुशल कार्यान्वयन है।


1

पिछले उत्तरों के शीर्ष पर, ढेर में ढेर संरचना संपत्ति होनी चाहिए; पेड़ को पूरा भरा होना चाहिए, और सबसे नीचे की परत, जो हमेशा भरी नहीं रह सकती है, को बिना किसी अंतराल के सबसे बाईं ओर भरना चाहिए।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.