जवाबों:
बाइनरी-पेड़ों के प्रदर्शन के बारे में व्यंग्य करने के लिए अर्थहीन है - वे एक डेटा संरचना नहीं हैं, लेकिन डेटा संरचनाओं का परिवार, सभी अलग-अलग प्रदर्शन विशेषताओं के साथ। हालांकि यह सच है कि असंतुलित बाइनरी पेड़ खोज के लिए सेल्फ-बैलेंसिंग बाइनरी पेड़ों की तुलना में बहुत खराब प्रदर्शन करते हैं, कई बाइनरी ट्री (जैसे बाइनरी कोशिशें) हैं जिनके लिए "संतुलन" का कोई अर्थ नहीं है।
map
और set
ऑब्जेक्ट।खोज के लिए n-ary पेड़ों की तुलना में बाइनरी पेड़ों का उपयोग अधिक बार किया जाता है, यह है कि n-ary पेड़ अधिक जटिल होते हैं, लेकिन आमतौर पर कोई वास्तविक गति लाभ नहीं देते हैं।
m
नोड्स के साथ एक संतुलित (संतुलित) बाइनरी ट्री में , एक स्तर से दूसरे स्तर तक जाने के लिए एक तुलना की आवश्यकता होती है, और log_2(m)
कुल log_2(m)
तुलना के लिए स्तर होते हैं ।
इसके विपरीत, एन-एरी ट्री को अगले स्तर पर जाने के लिए log_2(n)
तुलना (एक बाइनरी खोज का उपयोग करके) की आवश्यकता होगी । चूंकि log_n(m)
कुल स्तर हैं, खोज के लिए कुल log_2(n)*log_n(m)
= log_2(m)
तुलना की आवश्यकता होगी । इसलिए, हालांकि एन-एरी पेड़ अधिक जटिल हैं, वे आवश्यक कुल तुलनाओं के संदर्भ में कोई लाभ नहीं देते हैं।
(हालांकि, एन-एरी ट्री अभी भी आला-स्थितियों में उपयोगी हैं। तुरंत दिमाग में आने वाले उदाहरण क्वाड-ट्री और अन्य अंतरिक्ष-विभाजन वाले पेड़ हैं, जहां केवल दो नोड प्रति स्तर का उपयोग करके अंतरिक्ष को विभाजित करना तर्क को अनावश्यक रूप से जटिल बना देगा; कई डेटाबेस में उपयोग किए जाने वाले बी-पेड़ , जहां सीमित कारक प्रत्येक स्तर पर कितनी तुलनाएं की जाती हैं, लेकिन हार्ड ड्राइव से एक ही बार में कितने नोड लोड किए जा सकते हैं)
जब अधिकांश लोग बाइनरी पेड़ों के बारे में बात करते हैं, तो वे बाइनरी सर्च ट्री के बारे में नहीं सोचने की तुलना में अधिक बार होते हैं, इसलिए मैं इसे पहले कवर करूंगा।
एक गैर-संतुलित बाइनरी खोज पेड़ वास्तव में डेटा संरचनाओं के बारे में छात्रों को शिक्षित करने की तुलना में बहुत अधिक उपयोगी है। ऐसा इसलिए है, क्योंकि जब तक डेटा अपेक्षाकृत यादृच्छिक क्रम में नहीं आ रहा है, तब तक पेड़ आसानी से अपने सबसे खराब स्थिति में बदल सकता है, जो एक लिंक की गई सूची है, क्योंकि साधारण बाइनरी पेड़ संतुलित नहीं हैं ।
बिंदु में एक अच्छा मामला: मुझे एक बार कुछ सॉफ़्टवेयर को ठीक करना पड़ा जिसने अपने डेटा को हेरफेर और खोज के लिए एक द्विआधारी पेड़ में लोड किया। इसने डेटा को क्रमबद्ध रूप में लिखा:
Alice
Bob
Chloe
David
Edwina
Frank
ताकि, जब इसे वापस पढ़ा जाए, तो निम्नलिखित पेड़ के साथ समाप्त हो गया:
Alice
/ \
= Bob
/ \
= Chloe
/ \
= David
/ \
= Edwina
/ \
= Frank
/ \
= =
जो पतित रूप है। यदि आप उस पेड़ में फ्रैंक की तलाश में जाते हैं, तो आपको उसे खोजने से पहले सभी छह नोड्स की खोज करनी होगी।
जब आप उन्हें संतुलित करते हैं, तो खोज के लिए बाइनरी ट्री वास्तव में उपयोगी हो जाते हैं। इसमें उप-वृक्षों को उनके मूल नोड के माध्यम से घुमाना शामिल है ताकि किसी भी दो उप-वृक्षों के बीच की ऊँचाई का अंतर 1 से कम या बराबर हो। एक संतुलित पेड़ में एक समय में एक से ऊपर नाम जोड़ने से आपको निम्नलिखित अनुक्रम मिलेगा:
1. Alice
/ \
= =
2. Alice
/ \
= Bob
/ \
= =
3. Bob
_/ \_
Alice Chloe
/ \ / \
= = = =
4. Bob
_/ \_
Alice Chloe
/ \ / \
= = = David
/ \
= =
5. Bob
____/ \____
Alice David
/ \ / \
= = Chloe Edwina
/ \ / \
= = = =
6. Chloe
___/ \___
Bob Edwina
/ \ / \
Alice = David Frank
/ \ / \ / \
= = = = = =
आप वास्तव में पूरे उप-पेड़ों को बाईं ओर (चरण 3 और 6 में) घुमाते हुए देख सकते हैं क्योंकि प्रविष्टियाँ जोड़ी जाती हैं और यह आपको एक संतुलित बाइनरी ट्री देता है जिसमें सबसे खराब स्थिति लुकअप के O(log N)
बजाय होती है O(N
) जो कि पतित रूप देता है। किसी भी बिंदु पर उच्चतम NULL ( =
) निम्नतम से एक स्तर से भिन्न नहीं होता है। और, इसके बाद के संस्करण अंतिम पेड़ में, आप फ्रैंक केवल तीन नोड्स को देखकर पा सकते हैं ( Chloe
, Edwina
और, अंत में, Frank
)।
बेशक, वे तब और भी उपयोगी हो सकते हैं जब आप उन्हें बाइनरी ट्रेस के बजाय संतुलित बहु-स्तरीय पेड़ बनाते हैं। इसका मतलब है कि प्रत्येक नोड में एक से अधिक आइटम हैं (तकनीकी रूप से, वे एन आइटम और एन + 1 पॉइंटर्स रखते हैं, एक बाइनरी ट्री 1 आइटम और 2 पॉइंटर्स के साथ 1-वे मल्टी-वे ट्री का एक विशेष मामला है)।
तीन-तरफा पेड़ के साथ, आप समाप्त होते हैं:
Alice Bob Chloe
/ | | \
= = = David Edwina Frank
/ | | \
= = = =
यह आमतौर पर मदों की एक सूची के लिए चाबियाँ बनाए रखने में उपयोग किया जाता है। मैंने डेटाबेस सॉफ़्टवेयर को हार्डवेयर के लिए अनुकूलित लिखा है, जहाँ एक नोड डिस्क ब्लॉक के आकार का होता है (जैसे, 512 बाइट्स) और आप एक ही नोड में जितनी अधिक कुंजी डाल सकते हैं, उतने कुंजी डालते हैं। संकेत इस मामले में वास्तव में एक निश्चित लंबाई रिकॉर्ड प्रत्यक्ष अभिगम फ़ाइल सूचकांक फ़ाइल से अलग में रिकॉर्ड संख्या में थे (ताकि रिकार्ड संख्या X
सिर्फ करने की मांग से पाया जा सकता है X * record_length
)।
उदाहरण के लिए, यदि पॉइंटर्स 4 बाइट्स हैं और कुंजी का आकार 10 है, तो 512-बाइट नोड में कुंजियों की संख्या 36 है। कुल 508 बाइट्स के लिए 36 कुंजी (360 बाइट्स) और 37 पॉइंटर्स (148 बाइट्स) हैं। 4 बाइट्स प्रति नोड बर्बाद।
मल्टी-वे कीज़ का उपयोग दो-चरण खोज की जटिलता का परिचय देता है (नोड में सही कुंजी खोजने के लिए एक छोटे अनुक्रमिक (या रैखिक बाइनरी) खोज के साथ संयुक्त सही नोड को खोजने के लिए बहु-तरीका खोज) लेकिन में लाभ कम डिस्क I / O इससे अधिक करने के लिए बनाता है।
मुझे इन-मेमोरी संरचना के लिए ऐसा करने का कोई कारण नहीं दिखता है, आप संतुलित बाइनरी ट्री के साथ चिपके रहना और अपना कोड सरल रखना बेहतर होगा।
यह भी ध्यान रखें कि जब आपके डेटा सेट छोटे होते हैं तो O(log N)
ओवर के फायदे O(N)
वास्तव में दिखाई नहीं देते हैं। यदि आप अपनी पता पुस्तिका में पंद्रह लोगों को संग्रहीत करने के लिए बहु-प्रकार के पेड़ का उपयोग कर रहे हैं, तो यह संभवतः ओवरकिल है। लाभ तब होता है जब आप पिछले दस वर्षों में अपने सौ हजार ग्राहकों से हर ऑर्डर की तरह कुछ स्टोर कर रहे होते हैं।
बड़े-ओ संकेतन के पूरे बिंदु को इंगित करना है कि क्या होता है N
दृष्टिकोण अनंत के रूप में । कुछ लोग असहमत हो सकते हैं, लेकिन बबल सॉर्ट का उपयोग करना ठीक है, यदि आपको यकीन है कि डेटा सेट एक निश्चित आकार से नीचे रहेंगे, जब तक कि कुछ और आसानी से उपलब्ध न हो :-)
बाइनरी पेड़ों के लिए अन्य उपयोगों के रूप में, बहुत सारे हैं, जैसे:
यह देखते हुए कि मैंने खोज पेड़ों के लिए कितनी व्याख्या की है, मैं दूसरों पर बहुत विस्तार करने के लिए मितभाषी हूं, लेकिन उन्हें अनुसंधान के लिए पर्याप्त होना चाहिए, क्या आपको इच्छा होनी चाहिए।
मोर्स कोड का संगठन एक बाइनरी ट्री है।
एक बाइनरी ट्री एक पेड़ डेटा संरचना है जिसमें प्रत्येक नोड में अधिकांश दो बच्चे नोड होते हैं, जिन्हें आमतौर पर "बाएं" और "दाएं" के रूप में प्रतिष्ठित किया जाता है। बच्चों के साथ नोड्स पैरेंट नोड्स हैं, और चाइल्ड नोड्स में उनके माता-पिता के संदर्भ हो सकते हैं। पेड़ के बाहर, अक्सर "रूट" नोड (सभी नोड्स के पूर्वज) का संदर्भ होता है, अगर यह मौजूद है। डेटा संरचना में किसी भी नोड को रूट नोड पर शुरू करके और बार-बार बाएं या दाएं बच्चे के संदर्भों तक पहुंचा जा सकता है। बाइनरी ट्री में प्रत्येक नोड की एक डिग्री अधिकतम दो होती है।
बाइनरी पेड़ उपयोगी होते हैं, क्योंकि जैसा कि आप तस्वीर में देख सकते हैं, यदि आप पेड़ में कोई भी नोड ढूंढना चाहते हैं, तो आपको केवल अधिकतम 6 बार देखना होगा। यदि आप नोड 24 की खोज करना चाहते हैं, उदाहरण के लिए, आप रूट पर शुरू करेंगे।
यह खोज नीचे दी गई है:
आप देख सकते हैं कि आप पहले पास के पूरे पेड़ के आधे नोड्स को बाहर कर सकते हैं। और दूसरे पर बाएं सबट्री का आधा हिस्सा। यह बहुत प्रभावी खोजों के लिए बनाता है। यदि यह 4 बिलियन पर किया गया था तत्वों , तो आपको अधिकतम 32 बार ही खोजना होगा। इसलिए, पेड़ में निहित अधिक तत्व, आपकी खोज जितनी अधिक कुशल हो सकती है।
विलोपन जटिल हो सकते हैं। यदि नोड में 0 या 1 बच्चा है, तो यह केवल हटाने के लिए कुछ बिंदुओं को स्थानांतरित करने की बात है। हालांकि, आप आसानी से 2 बच्चों के साथ एक नोड को हटा नहीं सकते हैं। इसलिए हम शॉर्ट कट लेते हैं। मान लीजिए कि हम नोड 19 को हटाना चाहते हैं।
चूंकि यह निर्धारित करने की कोशिश करना कि बाएं और दाएं पॉइंटर्स को कहां स्थानांतरित करना आसान नहीं है, हम इसे एक विकल्प के साथ ढूंढते हैं। हम बायें उप-वृक्ष पर जाते हैं, और जहाँ तक जा सकते हैं, वहाँ तक जाते हैं। यह हमें उस नोड का अगला सबसे बड़ा मूल्य देता है जिसे हम हटाना चाहते हैं।
अब हम बाएं और दाएं बिंदुओं को छोड़कर, सभी 18 सामग्री की प्रतिलिपि बनाते हैं, और मूल 18 नोड को हटा देते हैं।
इन छवियों को बनाने के लिए, मैंने एक AVL ट्री, एक सेल्फ बैलेंसिंग ट्री को लागू किया, ताकि किसी भी समय, पेड़ में पत्ती के नोड्स (बिना बच्चों वाले नोड्स) के बीच अंतर का अधिकतम एक स्तर हो। यह पेड़ को तिरछा होने से बचाता है और अतिरिक्त O(log n)
खोज समय को बनाए रखता है , आवेषण और विलोपन के लिए थोड़ा अधिक समय की लागत के साथ।
यहां एक नमूना दिखाया गया है कि कैसे मेरे एवीएल पेड़ ने खुद को यथासंभव कॉम्पैक्ट और संतुलित रखा है।
एक क्रमबद्ध सरणी में, लुकअप अभी भी O(log(n))
एक पेड़ की तरह लगेगा , लेकिन यादृच्छिक सम्मिलन और निष्कासन वृक्ष की जगह O (n) लेगा O(log(n))
। कुछ एसटीएल कंटेनर इन प्रदर्शन विशेषताओं का उपयोग अपने लाभ के लिए करते हैं इसलिए सम्मिलन और हटाने का समय अधिकतम होता है O(log n)
, जो बहुत तेज़ है। इन कंटेनरों में से कुछ हैं map
, multimap
, set
, औरmultiset
।
एवीएल पेड़ के लिए उदाहरण कोड http://ideone.com/MheW8 पर पाया जा सकता है
मुख्य आवेदन बाइनरी सर्च ट्री है । ये एक डेटा संरचना है जिसमें खोज, सम्मिलन और निष्कासन सभी बहुत तेज़ हैं ( log(n)
संचालन के बारे में )
एक द्विआधारी वृक्ष का एक दिलचस्प उदाहरण जिसका उल्लेख नहीं किया गया है, वह एक गणितीय मूल्यांकन के पुनरावर्ती मूल्यांकन है। यह मूल रूप से एक व्यावहारिक दृष्टिकोण से बेकार है, लेकिन यह इस तरह के भावों के बारे में सोचने का एक दिलचस्प तरीका है।
मूल रूप से पेड़ के प्रत्येक नोड का एक मूल्य होता है जो या तो स्वयं अंतर्निहित होता है या अपने बच्चों के मूल्यों पर काम करके पुनरावर्ती द्वारा मूल्यांकन किया जाता है।
उदाहरण के लिए, अभिव्यक्ति (1+3)*2
को इस प्रकार व्यक्त किया जा सकता है:
*
/ \
+ 2
/ \
1 3
अभिव्यक्ति का मूल्यांकन करने के लिए, हम माता-पिता का मूल्य पूछते हैं। यह नोड बदले में अपने बच्चों, एक प्लस ऑपरेटर और एक नोड से प्राप्त करता है जिसमें बस '2' होता है। प्लस ऑपरेटर बदले में '1' और '3' वाले बच्चों से अपने मूल्यों को प्राप्त करता है और उन्हें जोड़ता है, 4 को गुणा नोड पर लौटाता है जो 8 पर लौटता है।
एक बाइनरी ट्री का यह उपयोग एक अर्थ में पॉलिश नोटेशन को उल्टा करने के लिए एक समान है, इस क्रम में जिस क्रम में प्रदर्शन किया जाता है वह समान है। यह भी ध्यान देने वाली एक बात यह है कि इसके लिए बाइनरी ट्री होना जरूरी नहीं है, यह सिर्फ इतना है कि आमतौर पर इस्तेमाल किए जाने वाले ऑपरेटर बाइनरी हैं। अपने सबसे बुनियादी स्तर पर, बाइनरी ट्री वास्तव में सिर्फ एक बहुत ही सरल विशुद्ध रूप से कार्यात्मक प्रोग्रामिंग भाषा है।
मुझे नहीं लगता कि "शुद्ध" बाइनरी पेड़ों के लिए कोई उपयोग है। (शैक्षिक उद्देश्यों को छोड़कर) संतुलित बाइनरी पेड़, जैसे कि रेड-ब्लैक ट्री या एवीएल पेड़ अधिक उपयोगी होते हैं, क्योंकि वे ओ (लॉगन) संचालन की गारंटी देते हैं। सामान्य बाइनरी पेड़ एक सूची (या लगभग सूची) होने का अंत कर सकते हैं और बहुत डेटा का उपयोग करके अनुप्रयोगों में वास्तव में उपयोगी नहीं हैं।
संतुलित पेड़ों का उपयोग अक्सर नक्शे या सेट को लागू करने के लिए किया जाता है। उनका उपयोग ओ (नॉग्लन) में छंटाई के लिए भी किया जा सकता है, यहां तक कि इसे करने के बेहतर तरीके मौजूद हैं।
साथ ही हैश टेबल को खोजने / डालने / हटाने के लिए उपयोग किया जा सकता है, जिसमें आमतौर पर द्विआधारी खोज पेड़ों (संतुलित या नहीं) की तुलना में बेहतर प्रदर्शन होता है।
एक आवेदन जहां (संतुलित) द्विआधारी खोज पेड़ उपयोगी होगा यदि खोज / डालने / हटाने और छंटाई की आवश्यकता होगी। सॉर्ट इन-प्लेस (लगभग, पुनरावर्तन के लिए आवश्यक स्टैक स्थान की अनदेखी) हो सकता है, एक तैयार बिल्ड संतुलित पेड़ दिया जाता है। यह अभी भी O (nlogn) होगा, लेकिन एक छोटे से स्थिर कारक के साथ और कोई अतिरिक्त स्थान की आवश्यकता नहीं है (नए सरणी को छोड़कर, यह मानते हुए कि डेटा को एक सरणी में रखा जाना है)। दूसरी ओर हैश टेबल को छांटा नहीं जा सकता (कम से कम सीधे नहीं)।
शायद वे कुछ करने के लिए कुछ परिष्कृत एल्गोरिदम में भी उपयोगी होते हैं, लेकिन मेरे दिमाग में tbh कुछ भी नहीं आता है। अगर मुझे और मिलता है तो मैं अपनी पोस्ट संपादित करूंगा।
डेटाबेस में फ़े बी + ट्री जैसे अन्य पेड़ों का व्यापक रूप से उपयोग किया जाता है
सबसे आम एप्लिकेशन में से एक है संग्रहित तत्वों को जल्दी से संग्रहीत तत्वों तक पहुंचने और खोज करने के लिए कुशलतापूर्वक डेटा को स्टोर करना। उदाहरण के लिए, std::map
याstd::set
C ++ स्टैंडर्ड लाइब्रेरी में।
डेटा संरचना के रूप में बाइनरी ट्री अभिव्यक्ति पार्सर और अभिव्यक्ति सॉल्वर के विभिन्न कार्यान्वयन के लिए उपयोगी है।
इसका उपयोग डेटाबेस की कुछ समस्याओं को हल करने के लिए भी किया जा सकता है, उदाहरण के लिए, अनुक्रमण।
आमतौर पर, बाइनरी ट्री विशेष रूप से ट्री-आधारित डेटा संरचना की एक सामान्य अवधारणा है और विभिन्न गुणों के साथ विभिन्न प्रकार के बाइनरी ट्री का निर्माण किया जा सकता है।
C ++ STL में, और अन्य भाषाओं में कई अन्य मानक लाइब्रेरी, जैसे जावा और C #। बाइनरी सर्च ट्री का उपयोग सेट और मैप को लागू करने के लिए किया जाता है।
बाइनरी पेड़ों के सबसे महत्वपूर्ण अनुप्रयोगों में से एक संतुलित बाइनरी सर्च ट्री हैं जैसे:
इस प्रकार के पेड़ों में संपत्ति होती है कि बाएं सबट्री और राइट सबट्री की ऊंचाइयों में अंतर प्रत्येक बार घुमाव जैसे ऑपरेशन करके छोटा किया जाता है जब एक नोड डाला जाता है या हटा दिया जाता है।
इसके कारण, पेड़ की समग्र ऊंचाई लॉग एन के क्रम के बनी हुई है और नोड्स के खोज, सम्मिलन और विलोपन जैसे संचालन ओ (लॉग एन) समय में किए जाते हैं। C ++ का STL भी इन पेड़ों को सेट और नक्शे के रूप में लागू करता है।
आधुनिक हार्डवेयर पर, एक बाइनरी ट्री लगभग हमेशा खराब कैश और अंतरिक्ष व्यवहार के कारण उप-रूपी होता है। यह भी (अर्ध) संतुलित वेरिएंट के लिए जाता है। यदि आप उन्हें ढूंढते हैं, तो यह वह जगह है जहां प्रदर्शन की गणना नहीं होती है (या तुलनात्मक कार्य का वर्चस्व है), या ऐतिहासिक या अज्ञानता के कारणों की अधिक संभावना है।
एक कंपाइलर जो एक एएसटी के प्रतिनिधित्व के लिए एक द्विआधारी पेड़ का उपयोग करता है, वह पोस्टऑर्डर, इनवर्टर जैसे पेड़ को पार्स करने के लिए ज्ञात एल्गोरिदम का उपयोग कर सकता है। प्रोग्रामर को स्वयं एल्गोरिथ्म के साथ आने की आवश्यकता नहीं है। क्योंकि स्रोत फ़ाइल के लिए एक बाइनरी ट्री n-ary ट्री की तुलना में अधिक है, इसलिए इसके निर्माण में अधिक समय लगता है। इस उत्पादन को लें: selstmnt: = "if" ("expr") "stmnt" ELSE "stmnt एक बाइनरी ट्री में यह 3levels के नोड्स होंगे, लेकिन n-ary ट्री में 1 स्तर (chids का) होगा
यही कारण है कि यूनिक्स आधारित ओएस-एस धीमी हैं।