मेमोरी, फायदे और नुकसान में ग्राफ को स्टोर करने के तीन तरीके


90

स्मृति में ग्राफ़ को संग्रहीत करने के तीन तरीके हैं:

  1. संकेत के रूप में वस्तुओं और किनारों के रूप में नोड्स
  2. एक मैट्रिक्स जिसमें धारित नोड x और नोड y के बीच सभी किनारे वजन होते हैं
  3. गिने हुए नोड्स के बीच किनारों की एक सूची

मुझे पता है कि तीनों को कैसे लिखना है, लेकिन मुझे यकीन नहीं है कि मैंने सभी के फायदे और नुकसान के बारे में सोचा है।

स्मृति में ग्राफ़ को संग्रहीत करने के इन तरीकों में से प्रत्येक के फायदे और नुकसान क्या हैं?


3
मैं मैट्रिक्स पर तभी विचार करूंगा जब ग्राफ बहुत जुड़ा हुआ हो या बहुत छोटा हो। बेहद जुड़े हुए ग्राफ़ के लिए, ऑब्जेक्ट / पॉइंटर या किनारों के दृष्टिकोण की सूची दोनों ही बेहतर मेमोरी का उपयोग करेंगे। मैं उत्सुक हूं कि भंडारण के अलावा मैंने क्या अनदेखी की है। ;)
sarnold

2
वे समय जटिलता में भी भिन्न होते हैं, मैट्रिक्स O (1) है, और अन्य अभ्यावेदन आप जो खोज रहे हैं उसके आधार पर व्यापक रूप से भिन्न हो सकते हैं।
msw

1
मुझे याद है कि कुछ समय पहले एक ग्राफ को पॉइंटर्स की सूची पर एक मैट्रिक्स के रूप में लागू करने के हार्डवेयर लाभों का वर्णन करते हुए एक लेख पढ़ना। मैं इसके अलावा इसके बारे में ज्यादा याद नहीं कर सकता, जैसा कि आप स्मृति के एक सन्निहित ब्लॉक के साथ काम कर रहे हैं, किसी भी समय आपके काम के सेट का बहुत कुछ एल 2 कैश में हो सकता है। दूसरी ओर नोड्स / पॉइंटर्स की एक सूची को मेमोरी के माध्यम से बन्द किया जा सकता है और संभवतः एक ऐसे कैश की आवश्यकता होगी जो कैश को हिट नहीं करता है। मुझे यकीन नहीं है कि मैं सहमत हूं लेकिन यह एक दिलचस्प विचार है।
नेरगा

1
@ डीन जे: केवल "नोड्स के रूप में ऑब्जेक्ट्स और किनारों के रूप में पॉइंटर्स प्रतिनिधित्व" के बारे में एक प्रश्न। ऑब्जेक्ट में पॉइंटर्स को संग्रहीत करने के लिए आप किस डेटा संरचना का उपयोग करते हैं? क्या यह एक सूची है?
टिमोफे

4
सामान्य नाम हैं: (1) आसन्न सूची के बराबर , (2) आसन्न मैट्रिक्स , (3) बढ़त सूची
इवगेनी सर्गेव

जवाबों:


51

इनका विश्लेषण करने का एक तरीका स्मृति और समय की जटिलता के संदर्भ में है (जो इस बात पर निर्भर करता है कि आप ग्राफ़ को कैसे एक्सेस करना चाहते हैं)।

एक दूसरे के लिए संकेत के साथ वस्तुओं के रूप में नोड्स संचय करना

  • इस दृष्टिकोण के लिए मेमोरी जटिलता O (n) है क्योंकि आपके पास उतने ऑब्जेक्ट हैं जितने आपके पास नोड्स हैं। आवश्यक बिंदुओं की संख्या (नोड्स के लिए) O (n ^ 2) तक है क्योंकि प्रत्येक नोड ऑब्जेक्ट में n नोड्स तक के लिए पॉइंटर्स हो सकते हैं।
  • किसी भी दिए गए नोड तक पहुँचने के लिए इस डेटा संरचना की समय जटिलता O (n) है।

एज वेट का एक मैट्रिक्स स्टोर करना

  • यह मैट्रिक्स के लिए O (n ^ 2) की मेमोरी जटिलता होगी।
  • इस डेटा संरचना के साथ लाभ यह है कि किसी भी नोड को एक्सेस करने की समय जटिलता O (1) है।

ग्राफ़ पर आपके द्वारा चलाए जा रहे एल्गोरिदम और कितने नोड हैं, इसके आधार पर, आपको एक उपयुक्त प्रतिनिधित्व चुनना होगा।


3
मेरा मानना ​​है कि ऑब्जेक्ट / पॉइंटर मॉडल में खोजों के लिए समय जटिलता केवल O (n) है यदि आप नोड्स को एक अलग सरणी में संग्रहीत करते हैं। अन्यथा आपको वांछित नोड के लिए खोज करने वाले ग्राफ को पार करना होगा, नहीं? मनमाने ढंग से ग्राफ में हर नोड (लेकिन जरूरी नहीं कि हर किनारे) की ट्रे (नग O (n) में की जा सके, क्या ऐसा हो सकता है?
बैरी फ्रूटमैन

@BarryFruitman मुझे पूरा यकीन है कि आप सही हैं। BFS O (V + E) है। इसके अलावा, यदि आप एक नोड की खोज कर रहे हैं जो अन्य नोड्स से जुड़ा नहीं है, तो आप इसे कभी नहीं पाएंगे।
वाइल्डरफिल्ड

10

कुछ और बातों पर विचार करें:

  1. मैट्रिक्स मॉडल वज़न में किनारों के साथ रेखांकन करने के लिए अधिक आसानी से उधार देता है, मैट्रिक्स में भार को संग्रहीत करके। ऑब्जेक्ट / पॉइंटर मॉडल को एक समानांतर सरणी में किनारे भार को स्टोर करने की आवश्यकता होगी, जिसे पॉइंटर सरणी के साथ सिंक्रनाइज़ेशन की आवश्यकता होती है।

  2. ऑब्जेक्ट / पॉइंटर मॉडल अप्रत्यक्ष रेखांकन की तुलना में निर्देशित रेखांकन के साथ बेहतर काम करता है क्योंकि बिंदुओं को जोड़े में बनाए रखने की आवश्यकता होगी, जो कि अनसेंड्रेटेड हो सकते हैं।


1
आपका मतलब है कि अप्रत्यक्ष रेखांकन, सही के साथ जोड़े में बिंदुओं को बनाए रखने की आवश्यकता होगी? यदि इसे निर्देशित किया जाता है, तो आप किसी विशेष वर्टेक्स की आसन्न सूची में केवल एक शीर्ष जोड़ते हैं, लेकिन यदि यह अप्रत्यक्ष है, तो आपको दोनों कोने की आसन्न सूची में एक जोड़ना होगा?
FrostyStraw

@FrostyStraw हाँ, बिल्कुल।
बैरी फ्रूटमैन

8

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

मैं व्यक्तिगत रूप से आसन्न मेट्रिक्स से प्यार करता हूं क्योंकि वे बीजीय ग्राफ सिद्धांत से उपकरण का उपयोग करके सभी प्रकार की समस्याओं को बहुत आसान बनाते हैं। (आसन्न मैट्रिक्स की kth शक्ति, उदाहरण के लिए, उदाहरण के लिए, मैं शीर्ष से शीर्ष पर, कश्मीर की लंबाई के पथ की संख्या देता हूं। लंबाई = के पथ की संख्या प्राप्त करने के लिए kth शक्ति लेने से पहले एक पहचान मैट्रिक्स जोड़ें। एक रैंक लें। एन -1 लैपेलियन के नाबालिग पेड़ों की संख्या पाने के लिए ... और इसी तरह।)

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


7

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

अन्यथा, आप प्रत्येक नोड पर पॉइंटर्स से भरा एक सरणी (या हैशमैप) भी रख सकते हैं। यह O (1) को दिए गए नोड तक पहुंच प्रदान करता है, लेकिन मेमोरी उपयोग को थोड़ा बढ़ा देता है। यदि n नोड्स की संख्या है और e किनारों की संख्या है, तो इस दृष्टिकोण की अंतरिक्ष जटिलता O (n + e) ​​होगी।

मैट्रिक्स दृष्टिकोण के लिए अंतरिक्ष की जटिलता ओ (n ^ 2) की पंक्तियों के साथ होगी (यह मानते हुए कि किनारे अप्रत्यक्ष हैं)। यदि आपका ग्राफ विरल है, तो आपके मैट्रिक्स में बहुत सारी खाली कोशिकाएँ होंगी। लेकिन अगर आपका ग्राफ पूरी तरह से जुड़ा हुआ है (e = n ^ 2), तो यह पहले दृष्टिकोण के अनुकूल है। जैसा कि आरजी कहते हैं, आपके पास इस दृष्टिकोण के साथ कम कैश मिस हो सकता है यदि आप मैट्रिक्स को मेमोरी के एक चंक के रूप में आवंटित करते हैं, जो कि ग्राफ़ के चारों ओर बहुत अधिक तेजी से निम्नलिखित बना सकता है।

तीसरा दृष्टिकोण संभवतः अधिकांश मामलों के लिए सबसे अधिक कुशल है - O (e) - लेकिन किसी दिए गए नोड O (e) के सभी किनारों को खोजने का कार्य करेगा। मैं ऐसे मामले के बारे में नहीं सोच सकता जहाँ यह बहुत उपयोगी होगा।


क्रुकल के एल्गोरिथ्म के लिए किनारे की सूची स्वाभाविक है ("प्रत्येक किनारे के लिए, संघ-खोज में एक नज़र डालें")। इसके अलावा, स्कीना (2 एड।, पृष्ठ 157) अपनी लाइब्रेरी कॉम्बिनेटरिका (जो कई एल्गोरिदम का एक सामान्य-उद्देश्य पुस्तकालय है) में रेखांकन के लिए मूल डेटा संरचना के रूप में बढ़त सूचियों के बारे में बात करता है। उन्होंने उल्लेख किया है कि इसका एक कारण गणितज्ञ के कम्प्यूटेशनल मॉडल द्वारा लगाए गए अवरोध हैं, जो कि पर्यावरण है जिसमें कॉम्बिनेटरिका रहता है।
इवगेनी सर्गेव

5

पर एक नज़र डालें विकिपीडिया तुलना तालिका देखें। यह रेखांकन के प्रत्येक प्रतिनिधित्व का उपयोग करते समय बहुत अच्छी समझ देता है।


4

एक और विकल्प है: ऑब्जेक्ट्स के रूप में नोड्स, ऑब्जेक्ट्स के रूप में किनारों, प्रत्येक किनारे दो दोहरे लिंक वाली सूचियों में एक ही समय में: एक ही नोड से निकलने वाले सभी किनारों की सूची और एक ही नोड में जाने वाले सभी किनारों की सूची ।

struct Node {
    ... node payload ...
    Edge *first_in;    // All incoming edges
    Edge *first_out;   // All outgoing edges
};

struct Edge {
    ... edge payload ...
    Node *from, *to;
    Edge *prev_in_from, *next_in_from; // dlist of same "from"
    Edge *prev_in_to, *next_in_to;     // dlist of same "to"
};

मेमोरी ओवरहेड बड़ा है (2 पॉइंट प्रति नोड और 6 पॉइंट प्रति एज) लेकिन आपको मिलता है

  • O (1) नोड सम्मिलन
  • O (1) एज इंसर्शन ("से" और "से" नोड्स को संकेत दिया गया)
  • O (1) एज डिलीट (पॉइंटर दिया गया)
  • O (नीचे (n)) नोड विलोपन (सूचक दिया गया)
  • O (नीच) (n) एक नोड के पड़ोसियों को खोजना

संरचना भी बल्कि सामान्य ग्राफ का प्रतिनिधित्व कर सकती है: छोरों के साथ उन्मुख मल्टीग्राफ (यानी आप एक ही दो नोड्स के बीच कई अलग-अलग किनारों को शामिल कर सकते हैं जिसमें कई अलग-अलग छोरों - x से x तक जाने वाले किनारे) शामिल हैं।

इस दृष्टिकोण का अधिक विस्तृत विवरण यहां उपलब्ध है


3

ठीक है, इसलिए यदि किनारों में वज़न नहीं है, तो मैट्रिक्स एक बाइनरी सरणी हो सकता है, और बाइनरी ऑपरेटर्स का उपयोग करके उस मामले में चीजें वास्तव में तेज हो सकती हैं।

यदि ग्राफ़ विरल है, तो ऑब्जेक्ट / पॉइंटर विधि बहुत अधिक कुशल लगती है। किसी डेटा संरचना में ऑब्जेक्ट / पॉइंटर्स को पकड़ना विशेष रूप से उन्हें मेमोरी के एक ही हिस्से में समेटना भी एक अच्छी योजना हो सकती है, या उन्हें साथ रहने का कोई अन्य तरीका भी हो सकता है।

आसन्न सूची - बस जुड़े नोड्स की एक सूची - अब तक सबसे अधिक स्मृति कुशल लगती है, लेकिन शायद सबसे धीमी भी।

एक निर्देशित ग्राफ पीछे है आसान और मैट्रिक्स प्रतिनिधित्व के साथ, आसान निकटता की सूची के साथ है, लेकिन वस्तु / सूचक प्रतिनिधित्व के साथ इतना बड़ा नहीं।

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