लाल-काले पेड़ इतने लोकप्रिय क्यों हैं?


46

ऐसा लगता है कि हर जगह मैं देखता हूं, लाल-काले पेड़ों ( std::setसी ++ में, SortedDictionaryसी #, आदि) का उपयोग करके डेटा संरचनाएं लागू की जा रही हैं ।

मेरे एल्गोरिदम वर्ग में सिर्फ (क, ख), लाल-काले और AVL के पेड़ों को कवर करने के बाद, यहाँ जो मुझे मिला (वह भी प्राध्यापकों से पूछकर, कुछ किताबों को देखकर और थोड़ा गुगला करके):

  • एवीएल पेड़ों में लाल-काले पेड़ों की तुलना में छोटी औसत गहराई होती है, और इस तरह एवीएल पेड़ में एक मूल्य की खोज लगातार तेज होती है।
  • एवीएल पेड़ों की तुलना में लाल-काले पेड़ अपने आप को संतुलित करने के लिए कम संरचनात्मक परिवर्तन करते हैं, जो उन्हें सम्मिलित / हटाने के लिए संभावित रूप से तेज़ कर सकते हैं। मैं संभावित रूप से कह रहा हूं, क्योंकि यह पेड़ के संरचनात्मक परिवर्तन की लागत पर निर्भर करेगा, क्योंकि यह रनटाइम और इम्प्लिमेंटेशन पर बहुत कुछ निर्भर करेगा (पेड़ के अपरिवर्तनीय होने पर एक कार्यात्मक भाषा में भी पूरी तरह से अलग हो सकता है?)

ऑनलाइन कई बेंचमार्क हैं जो एवीएल और लाल-काले पेड़ों की तुलना करते हैं, लेकिन मुझे क्या फायदा हुआ कि मेरे प्रोफेसर ने मूल रूप से कहा, कि आमतौर पर आप दो चीजों में से एक करते हैं:

  • या तो आप वास्तव में प्रदर्शन के बारे में इतना ध्यान नहीं रखते हैं, जिसमें ज्यादातर मामलों में एवीएल बनाम रेड-ब्लैक का 10-20% अंतर बिल्कुल भी मायने नहीं रखेगा।
  • या आप वास्तव में प्रदर्शन के बारे में परवाह करते हैं, जिसमें आप एवीएल और लाल-काले दोनों पेड़ों को खोदते हैं, और बी-पेड़ों के साथ जाते हैं, जिसे बेहतर काम करने के लिए ट्वीक किया जा सकता है (या (ए, बी) -ट्रीज़, मैं ' मैं उन सभी को एक टोकरी में रखने वाला हूं।)

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

समस्या यह है कि मुझे लगभग कोई ऐसा स्रोत नहीं मिला है जो वास्तविक आधुनिक हार्डवेयर पर खोज पेड़ों के विभिन्न कार्यान्वयनों के वास्तविक जीवन उपयोग का विश्लेषण करेगा। मैंने एल्गोरिदम पर कई पुस्तकों के माध्यम से देखा है और ऐसा कुछ भी नहीं पाया है जो अलग-अलग पेड़ वेरिएंट की एक साथ तुलना करेगा, यह दिखाने के अलावा कि दूसरे की तुलना में छोटी औसत गहराई है (जो वास्तव में पेड़ के व्यवहार के बारे में बहुत कुछ नहीं कहता है। वास्तविक कार्यक्रमों में।)

यह कहा जा रहा है, क्या कोई विशेष कारण है कि हर जगह लाल-काले पेड़ों का उपयोग किया जा रहा है, जब ऊपर कही गई बातों के आधार पर, बी-पेड़ों को उखाड़ फेंकना चाहिए? (एकमात्र बेंचमार्क के रूप में मैं http://lh3lh3.users.sourceforge.net/udb.shtml भी दिखा सकता हूं , लेकिन यह केवल विशिष्ट कार्यान्वयन की बात हो सकती है)। या यही कारण है कि हर कोई लाल-काले पेड़ों का उपयोग करता है क्योंकि वे लागू करना आसान है, या इसे अलग-अलग शब्दों में कहें, तो खराब तरीके से लागू करना मुश्किल है?

इसके अलावा, यह कैसे बदलता है जब कोई कार्यात्मक भाषाओं के दायरे में जाता है? ऐसा लगता है कि क्लोजर और स्काला दोनों हीश एरे मैप्ड ट्राइ का उपयोग करते हैं, जहां क्लोजर 32 के ब्रांचिंग कारक का उपयोग करता है।


8
अपने दर्द को जोड़ने के लिए, अधिकांश लेख जो विभिन्न प्रकार के खोज पेड़ों की तुलना करते हैं ... आदर्श प्रयोगों से कम हैं।
राफेल

1
मैंने खुद इसे कभी नहीं समझा है, मेरी राय में एवीएल पेड़ों को लाल-काले पेड़ों (रिबैलेंसिंग के दौरान कम मामले) से लागू करना आसान है, और मैंने कभी भी प्रदर्शन में महत्वपूर्ण अंतर नहीं देखा है।
जोर्डी वर्मीलेन

3
Stackoverflow पर हमारे दोस्तों द्वारा एक प्रासंगिक चर्चा क्यों है std :: नक्शा एक लाल-काले पेड़ के रूप में लागू किया गया है?
हेंड्रिक जन

जवाबों:


10

" एवीएल पेड़ों और लाल काले पेड़ों में जड़ से Traversals " सवाल के जवाब से उद्धृत करने के लिए

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

तो एक RedBlack पेड़ डालने प्रत्यावर्तन के बिना लागू किया जा सकता, पर कुछ सीपीयू प्रत्यावर्तन है बहुत महंगा यदि आप उग आया समारोह कॉल कैश (जैसे स्पार्क के कारण का उपयोग है रजिस्टर खिड़की )

(मैंने एक फंक्शन कॉल को हटाकर स्पार्क पर 10 गुना तेजी से सॉफ्टवेयर देखा है, जिसके परिणामस्वरूप अक्सर कोड पथ को रजिस्टर विंडो के लिए बहुत गहरा कहा जाता है। जैसा कि आप नहीं जानते कि रजिस्टर विंडो कितनी गहरी होगी। आपके ग्राहक का सिस्टम, और आप नहीं जानते हैं कि "हॉट कोड पाथ" में कॉल स्टैक कितनी दूर है, पुनरावृत्ति का उपयोग न करके अधिक पूर्वानुमान जैसा है।)

स्टैक से बाहर नहीं निकलना भी एक लाभ है।


लेकिन 2 ^ 32 नोड्स वाले एक संतुलित पेड़ को लगभग 32 स्तरों की पुनरावृत्ति की आवश्यकता नहीं होगी। यहां तक ​​कि अगर आपका स्टैक फ्रेम 64 बाइट्स है, तो यह स्टैक स्पेस के 2 kb से अधिक नहीं है। क्या वाकई इससे फर्क पड़ सकता है? मुझे इसमें शक होगा।
ब्योर्न लिंडक्विस्ट

@ BjörnLindqvist, 1990 के दशक में SPARC प्रोसेसर पर, मैं अक्सर 7 से 6 की स्टैक गहराई से एक समान कोड पथ को बदलकर 10 गुना गति प्राप्त करता था! आगे पढ़िए इसने कैसे दर्ज की फाइलें ....
इयान रिंगरोज

9

मैं हाल ही में इस विषय पर शोध कर रहा हूं, इसलिए यहां मेरे निष्कर्ष हैं, लेकिन ध्यान रखें कि मैं डेटा संरचनाओं का विशेषज्ञ नहीं हूं!

कुछ ऐसे मामले हैं जहाँ आप B- पेड़ों का उपयोग नहीं कर सकते हैं।

एक प्रमुख मामला std::mapC ++ STL का है। मानक के लिए आवश्यक है कि insertवह मौजूदा पुनरावृत्तियों को अमान्य न करे

कोई पुनरावृत्तियों या संदर्भ अमान्य नहीं हैं।

http://en.cppreference.com/w/cpp/container/map/insert

यह बी-ट्री को एक नियम के रूप में लागू करता है क्योंकि सम्मिलन मौजूदा तत्वों के आसपास चलेगा।

एक और समान उपयोग का मामला घुसपैठ डेटास्ट्रक्चर है। अर्थात्, अपने डेटा को पेड़ के नोड के अंदर संग्रहीत करने के बजाय, आप अपनी संरचना के अंदर बच्चों / अभिभावकों को संकेत देते हैं:

// non intrusive
struct Node<T> {
    T value;
    Node<T> *left;
    Node<T> *right;
};
using WalrusList = Node<Walrus>;

// intrusive
struct Walrus {
    // Tree part
    Walrus *left;
    Walrus *right;

    // Object part
    int age;
    Food[4] stomach;
};

आप सिर्फ एक बी-ट्री को घुसपैठ नहीं बना सकते हैं, क्योंकि यह एक संकेतक-केवल डेटा संरचना नहीं है।

उदाहरण के लिए, लाल-काले पेड़ों का उपयोग किया जाता है, उदाहरण के लिए, मेमोरी के मुक्त ब्लॉक का प्रबंधन करने के लिए जेमलॉक में । यह लिनक्स कर्नेल में एक लोकप्रिय डेटा संरचना भी है।

मैं यह भी मानना है कि "एकल पास पूंछ पुनरावर्ती" कार्यान्वयन है नहीं एक के रूप में लाल, काले पेड़ लोकप्रियता के लिए कारण परिवर्तनशील डेटा संरचना।

सबसे पहले, स्टैक डेप्थ यहाँ अप्रासंगिक है, क्योंकि (दिए गए ऊंचाई) आप स्टैक स्पेस से बाहर चलाने से पहले मुख्य मेमोरी से बाहर चला जाएगा। Jemalloc के साथ खुश है preallocating स्टैक पर सबसे ज्यादा मामले गहराई।logn

लाल-काले पेड़ के कार्यान्वयन के कई स्वाद हैं। रॉबर्ट सेडगविक (कैओवर्ट) द्वारा एक प्रसिद्ध एक को लाल काले पेड़ों को छोड़ दिया जाता है ! अन्य वेरिएंट हैं जिन्हें "बाएं झुकाव" भी कहा जाता है, लेकिन एक अलग एल्गोरिथ्म का उपयोग करें)। यह वेरिएंट वास्तव में पेड़ के नीचे के रास्ते पर घुमाव प्रदर्शन करने की अनुमति देता है, लेकिन इसमें की महत्वपूर्ण संपत्ति में फिक्सअप की संख्या है, और यह इसे धीमा बनाता है ( जैसा कि जैमलॉक के लेखक द्वारा मापा गया है )। या, जैसा कि opendatastrutures डालता हैO(1)

एंडरसन के लाल-काले पेड़ों का संस्करण, लाल-काले पेड़ों के सेडग्विक का संस्करण, और एवीएल के पेड़ यहां परिभाषित रेडब्लैकट्री संरचना की तुलना में लागू करने के लिए सभी सरल हैं। दुर्भाग्य से, उनमें से कोई भी गारंटी नहीं दे सकता है कि पुनर्संतुलन में बिताए गए परिशोधन समय प्रति अद्यतन है।O(1)

ओपेंडैटैस्ट्रक्चर में वर्णित संस्करण पेरेंट पॉइंटर्स का उपयोग करता है, सम्मिलन के लिए एक पुनरावर्ती डाउन पास और फ़िक्सअप के लिए पुनरावृत्त लूप अप पास का उपयोग करता है। पुनरावर्ती कॉल एक पूंछ स्थिति में हैं और संकलक इसे एक लूप में अनुकूलित करते हैं (मैंने इसे रस्ट में जांचा है)।

यही है, यदि आप मूल बिंदुओं का उपयोग करते हैं, तो आप किसी भी लाल-काले जादू के बिना एक परिवर्तनशील खोज वृक्ष का निरंतर मेमोरी लूप कार्यान्वयन प्राप्त कर सकते हैं। यह बी-पेड़ों के लिए भी काम करता है। आपको सिंगल पास टेल रिकर्सिव इमम्यूट वैरिएंट के लिए जादू की जरूरत है, और यह वैसे भी ठीक कर देगा ।O(1)


3

खैर, यह एक आधिकारिक जवाब नहीं है, लेकिन जब भी मुझे एक संतुलित बाइनरी सर्च ट्री को कोड करना होता है, तो यह एक लाल-काला पेड़ होता है। इसके लिए कुछ कारण हैं:

1) औसत सम्मिलन लागत लाल-काले पेड़ों (यदि आपको खोजना नहीं है) के लिए स्थिर है, जबकि यह AVL पेड़ों के लिए लघुगणकीय है। इसके अलावा, इसमें अधिकतम एक जटिल पुनर्गठन शामिल है। यह अभी भी हे (लॉग एन) सबसे खराब स्थिति में है, लेकिन यह सिर्फ सरल पुनरावर्ती है।

2) उन्हें प्रति नोड केवल 1 बिट अतिरिक्त जानकारी की आवश्यकता होती है, और आप अक्सर इसे मुफ्त में प्राप्त करने का एक तरीका खोज सकते हैं।

3) मुझे बहुत बार ऐसा करने की ज़रूरत नहीं है, इसलिए हर बार जब मैं ऐसा करता हूं तो मुझे यह पता लगाना होता है कि यह कैसे करना है। 2-4 पेड़ों के साथ सरल नियम और पत्राचार हर बार आसान लगता है , भले ही कोड हर बार जटिल हो जाता है । मुझे अब भी उम्मीद है कि किसी दिन कोड सरल हो जाएगा।

४) जिस तरह से लाल-काले पेड़ से २-४ ट्री नोड विभाजित होते हैं और बीच की कुंजी को २-४ नोड में डालते हैं , ठीक उसी तरह से रीकोलिंग करके सुपर एलिगेंट हो जाता है। मैं इसे करने के लिए प्यार करता हूँ।


0

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

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


विडंबना यह है कि, लाल-काले पेड़ "ए (बी) के पेड़ों का एक विशेष मामला" केवल "हैं, इसलिए यह मामला मापदंडों के बंटवारे के लिए नीचे आता है? (सीसी @Gilles)
राफेल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.