माना जाता है कि उपरोक्त के आधार पर हमारे पास नोड और क्लास लिंक्डलिस्ट का एक सामान्य वर्ग है जो उपयोगकर्ता को जोड़ने, निकालने आदि की इजाजत देता है। अब, हम अपरिवर्तनीयता कैसे सुनिश्चित करेंगे?
आप ऑब्जेक्ट केवल पढ़ने के हर क्षेत्र बनाने, और यह सुनिश्चित करना है कि हर वस्तु के लिए उन केवल पढ़ने के क्षेत्रों में से एक भी अपरिवर्तनीय वस्तु है द्वारा संदर्भित द्वारा सुनिश्चित अचल स्थिति। यदि फ़ील्ड सभी पढ़े जाते हैं और केवल अन्य अपरिवर्तनीय डेटा का संदर्भ लेते हैं, तो स्पष्ट रूप से ऑब्जेक्ट अपरिवर्तनीय होगा!
क्या हम तत्व को सम्मिलित करते समय सूची में सभी संदर्भों की प्रतिलिपि बनाते हैं?
आप कर सकते थे। आप यहां जो भेद प्राप्त कर रहे हैं वह अपरिवर्तनीय और लगातार के बीच का अंतर है। एक अपरिवर्तनीय डेटा संरचना को बदला नहीं जा सकता है। लगातार डेटा संरचना इस तथ्य का लाभ उठाती है कि एक डेटा संरचना अपने हिस्सों का पुन: उपयोग करने के लिए अपरिवर्तनीय है।
एक लगातार अपरिवर्तनीय लिंक्ड सूची विशेष रूप से आसान है:
abstract class ImmutableList
{
public static readonly ImmutableList Empty = new EmptyList();
private ImmutableList() {}
public abstract int Head { get; }
public abstract ImmutableList Tail { get; }
public abstract bool IsEmpty { get; }
public abstract ImmutableList Add(int head);
private sealed class EmptyList : ImmutableList
{
public override int Head { get { throw new Exception(); } }
public override ImmutableList Tail { get { throw new Exception(); } }
public override bool IsEmpty { get { return true; } }
public override ImmutableList Add(int head)
{
return new List(head, this);
}
}
private sealed class List : ImmutableList
{
private readonly int head;
private readonly ImmutableList tail;
public override int Head { get { return head; } }
public override ImmutableList Tail { get { return tail; } }
public override bool IsEmpty { get { return false; } }
public override ImmutableList Add(int head)
{
return new List(head, this);
}
}
}
...
ImmutableList list1 = ImmutableList.Empty;
ImmutableList list2 = list1.Add(100);
ImmutableList list3 = list2.Add(400);
और वहाँ तुम जाओ। बेशक आप IEnumerable<int>
विधियों जैसे बेहतर अपवाद हैंडलिंग और अधिक विधियों को जोड़ना चाहते हैं। लेकिन एक निरंतर अपरिवर्तनीय सूची है। हर बार जब आप एक नई सूची बनाते हैं, तो आप मौजूदा अपरिवर्तनीय सूची की सामग्री का पुनः उपयोग करते हैं; list3 list2 की सामग्री का दोबारा उपयोग करता है, जो सुरक्षित रूप से कर सकता है क्योंकि list2 कभी नहीं बदलेगा।
क्या आपके कोई भी उत्तर दोगुनी-लिंक्ड सूचियों पर भी काम करेगा?
आप निश्चित रूप से एक दोगुनी-लिंक्ड सूची बना सकते हैं जो हर समय संपूर्ण डेटा संरचना की पूरी प्रतिलिपि करता है, लेकिन यह गूंगा होगा; आप बस एक सरणी का उपयोग कर सकते हैं और पूरे सरणी की प्रतिलिपि बना सकते हैं।
बनाना दोगुनी-लिंक्ड सूची काफी कठिन है लेकिन इसे करने के तरीके हैं। मैं क्या करूँगा दूसरी दिशा से समस्या का सामना करना है। कहने के बजाय "क्या मैं लगातार दोगुनी जुड़ी सूची बना सकता हूं?" खुद से पूछें "एक दोगुनी-लिंक्ड सूची के गुण क्या हैं जो मुझे आकर्षक लगते हैं?" उन गुणों को सूचीबद्ध करें और फिर देखें कि क्या आप लगातार डेटा संरचना के साथ आ सकते हैं जिसमें वे गुण हैं।
उदाहरण के लिए, यदि आपको पसंद की जाने वाली संपत्ति यह है कि यदि दोगुनी-लिंक्ड सूचियों को सस्ता रूप से किसी भी अंत से बढ़ाया जा सकता है, तो दो सूचियों में आधा रूप से टूटा हुआ हो सकता है, और दो सूचियों को सस्ती रूप से एक साथ जोड़ा जा सकता है, फिर आप जो लगातार संरचना चाहते हैं वह है एक अपरिवर्तनीय catenable डेक, एक दोगुनी लिंक वाली सूची नहीं। मैं एक अपरिवर्तनीय गैर catenable Deque का एक उदाहरण यहां दे:
http://blogs.msdn.com/b/ericlippert/archive/2008/02/12/immutability-in-c-part-eleven-a-working-double-ended-queue.aspx
यह विस्तार एक catenable Deque एक व्यायाम के रूप में छोड़ दिया जाता है कि; पेपर जो मैं उंगली के पेड़ से लिंक करता हूं वह पढ़ने के लिए एक अच्छा है।
अद्यतन:
ऊपर के अनुसार हम सम्मिलन बिंदु से ऊपर उपसर्ग कॉपी करना होगा। अपरिवर्तनीयता के तर्क से, यदि उपसर्ग से कुछ भी हटाते हैं, तो हमें एक नई सूची के साथ-साथ प्रत्यय में भी मिलता है ... फिर केवल उपसर्ग को कॉपी करने के लिए क्यों, और प्रत्यय नहीं है?
अच्छी तरह से एक उदाहरण पर विचार करें। क्या होगा अगर हमारे पास सूची (10, 20, 30, 40) है, और हम स्थिति 2 पर 25 डालना चाहते हैं? तो हम चाहते हैं (10, 20, 25, 30, 40)।
हम किन हिस्सों का पुन: उपयोग कर सकते हैं? हमारे पास पूंछ हैं (20, 30, 40), (30, 40) और (40)। स्पष्ट रूप से हम फिर से उपयोग कर सकते हैं (30, 40)।
आरेख तैयार करने से मदद मिल सकती है। हम:
10 ----> 20 ----> 30 -----> 40 -----> Empty
और हम चाहते हैं
10 ----> 20 ----> 25 -----> 30 -----> 40 -----> Empty
तो चलो
| 10 ----> 20 --------------> 30 -----> 40 -----> Empty
| /
| 10 ----> 20 ----> 25 -/
हम फिर से उपयोग (30, 40) कर सकते हैं क्योंकि वह हिस्सा दोनों सूचियों को आम में है बनाते हैं।
अद्यतन:
यह रूप में अच्छी तरह यादृच्छिक प्रविष्टि और हटाने के लिए कोड प्रदान करना संभव होगा?
ImmutableList InsertAt(int value, int position)
{
if (position < 0)
throw new Exception();
else if (position == 0)
return this.Add(value);
else
return tail.InsertAt(value, position - 1).Add(head);
}
आप देख क्यों यह काम करता है कार्य करें:
यहाँ एक पुनरावर्ती समाधान है?
अब एक अभ्यास के रूप में, एक रिकर्सिव DeleteAt लिखें।
अब, एक अभ्यास के रूप में, गैर-रिकर्सिव InsertAt और DeleteAt लिखें। याद रखें, आपके पास अपने निपटान पर एक अपरिवर्तनीय लिंक सूची है, इसलिए आप अपने पुनरावर्तक समाधान में से एक का उपयोग कर सकते हैं!
इसके लिए आपको बहुत बहुत धन्यवाद। बीटीडब्ल्यू, उपर्युक्त के अनुसार हमें सम्मिलन बिंदु तक उपसर्ग की प्रतिलिपि बनाने की आवश्यकता है। अपरिवर्तनीयता के तर्क से, यदि उपसर्ग से कुछ भी हटाते हैं, तो हमें एक नई सूची के साथ-साथ प्रत्यय में भी मिलता है ... फिर केवल उपसर्ग को कॉपी करने के लिए क्यों, और प्रत्यय नहीं है? – Bober02
क्या यादृच्छिक सम्मिलन और हटाने के लिए कोड प्रदान करना संभव होगा? बीटीडब्ल्यू। कतार, मानचित्र, पेड़ इत्यादि जैसी समान डेटा संरचनाओं के बारे में कोई कागजात/प्रश्न हैं – Bober02
धन्यवाद फिर एरिक, वास्तव में आपके समय की सराहना करते हैं। आशा है कि आपको इन दो साधारण प्रश्नों पर छोड़ने के लिए अनोखा मिनट होगा: आप कहते हैं कि "लगातार दोगुनी जुड़ी सूची" मुश्किल है। लगातार आप का क्या मतलब है? मैंने आपके अन्य प्रश्न पर भी टिप्पणी की जहां आपने लिखा था कि सम्मिलित पेड़ों का उपयोग करके सम्मिलन को लॉग (एन) में कम किया जा सकता है। क्या ऐसा इसलिए है क्योंकि अगर हम सही/बाएं सबट्री में डालते हैं तो हमें पेड़ के बाएं/दाएं भाग की प्रतिलिपि बनाने की आवश्यकता नहीं है? धन्यवाद फिर से – Bober02