2011-09-12 12 views
13

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

ऐसा करने का उचित तरीका क्या होगा? या मुझे किसी अन्य प्रकार के ढेर का उपयोग करना चाहिए?

नोट: मैंने यह पोस्ट Stack Clone Problem: .NET Bug or Expected Behaviour? देखा है, लेकिन यह सुनिश्चित नहीं है कि स्टैक क्लास के लिए क्लोन विधि कैसे सेट करें।

नोट # 2: मैं System.Collection.Generic.Stack

उत्तर

21
var clonedStack = new Stack<T>(new Stack<T>(oldStack)); 

आप इस एक विस्तार पद्धति के रूप में के रूप में

public static Stack<T> Clone<T>(this Stack<T> stack) { 
    Contract.Requires(stack != null); 
    return new Stack<T>(new Stack<T>(stack)); 
} 

यह आवश्यक है क्योंकि यह है कि हम कर रहे हैं Stack<T> निर्माता लिख ​​सकते हैं का उपयोग करें यहां उपयोग करके Stack<T>(IEnumerable<T> source) है और निश्चित रूप से जब आप IEnumerable<T> पर Stack<T> के लिए कार्यान्वयन करते हैं तो यह बार-बार स्टैक से आइटम पॉप करने जा रहा है जिससे आप उन्हें आदेश के विपरीत में खिला रहे हैं उन्हें नए ढेर पर जाने के लिए चींटी। इसलिए, इस प्रक्रिया को दो बार करने से परिणामस्वरूप सही क्रम में ढेर हो जाएगा।

वैकल्पिक रूप से:

var clonedStack = new Stack<T>(oldStack.Reverse()); 


public static Stack<T> Clone<T>(this Stack<T> stack) { 
    Contract.Requires(stack != null); 
    return new Stack<T>(stack.Reverse()); 
} 

फिर, हम ढेर से अधिक पुनरावृत्ति से उत्पादन से उलटे क्रम में ढेर चलना पड़ता है।

मुझे संदेह है कि इन दो तरीकों के बीच एक प्रदर्शन अंतर है।

var clone = new Stack<ElementType>(originalStack.Reverse()); 

आप एक विस्तार विधि बना सकते हैं बनाने के लिए इस आसान:

+0

उदासी, अजीब तरह से, इसी क्रम :(की रक्षा नहीं करता है (मुझे लगता है एक ढेर के दोहरे प्रारंभ गलती है तो या एक चाल है?) – SpaceBear

+0

@Angrius: यह क्रम बनाए रखने करता है डबल इन्स्टेन्शियशन एक चाल है कि कारण बनता है। आदेश संरक्षित करने के लिए। – jason

+1

@Angrius: "डबल प्रारंभिकरण" आवश्यक है क्योंकि प्रत्येक व्यक्ति आदेश को उलट देता है। यदि आप इसे दो बार उलट देते हैं तो आपको मूल ऑर्डर मिलता है। – Gabe

7

यहाँ एक आसान तरीका है, LINQ का उपयोग कर

public static class StackExtensions 
{ 
    public static Stack<T> Clone<T>(this Stack<T> source) 
    { 
     return new Stack<T>(originalStack.Reverse()); 
    } 
} 

उपयोग:

var clone = originalStack.Clone(); 
+0

उलझन में। रिवर्स क्यों? – SpaceBear

+0

धन्यवाद, सरल रिवर्स काम किया! – SpaceBear

+0

मेरे लिए काम किया। यह मूल ढेर को भी संरक्षित करता है। – MStodd

1

यदि आप डॉन ' टी को वास्तविक Stack`1 की आवश्यकता नहीं है, लेकिन बस मौजूदा Stack`1 की एक त्वरित प्रतिलिपि चाहते हैं कि y कहां उसी क्रम में चल सकता है कि Pop रिटर्न, दूसरा विकल्प Stack`1 को Queue`1 में डुप्लिकेट करना है। तत्व Dequeue उसी क्रम में होंगे कि वे Pop मूल Stack`1 से होंगे।

using System; 
using System.Collections.Generic; 

class Test 
{ 
    static void Main() 
    { 
    var stack = new Stack<string>(); 

    stack.Push("pushed first, pop last"); 
    stack.Push("in the middle"); 
    stack.Push("pushed last, pop first"); 

    var quickCopy = new Queue<string>(stack); 

    Console.WriteLine("Stack:"); 
    while (stack.Count > 0) 
     Console.WriteLine(" " + stack.Pop()); 
    Console.WriteLine(); 
    Console.WriteLine("Queue:"); 
    while (quickCopy.Count > 0) 
     Console.WriteLine(" " + quickCopy.Dequeue()); 
    } 
} 

आउटपुट:

 
Stack: 
    pushed last, pop first 
    in the middle 
    pushed first, pop last 

Queue: 
    pushed last, pop first 
    in the middle 
    pushed first, pop last 
2

जो लोग प्रदर्शन की देखभाल के लिए ..

public T[] Stack<T>.ToArray(); 
public void Stack<T>.CopyTo(T[] array, int arrayIndex); 

मैं एक किसी न किसी कार्यक्रम में लिखा था (लिंक पोस्ट के अंत में प्रदान किया जाएगा) प्रदर्शन को मापने और: वहाँ कुछ अन्य तरीके कैसे प्रदर्शन में बड़ी हानि के बिना मूल ढेर सदस्यों के माध्यम से पुनरावृति करने के लिए कर रहे हैं पहले से ही सुझाव दिया कार्यान्वयन के लिए दो टेस्ट जोड़ा, और दो टेस्ट (Clone1 और Clone2 देखें) toArray और CopyTo तरीकों के लिए (देखें Clone3 और Clone4, उन दोनों का उपयोग अधिक कुशल Array.Reverse विधि)।

public static class StackExtensions 
{ 
    public static Stack<T> Clone1<T>(this Stack<T> original) 
    { 
     return new Stack<T>(new Stack<T>(original)); 
    } 

    public static Stack<T> Clone2<T>(this Stack<T> original) 
    { 
     return new Stack<T>(original.Reverse()); 
    } 

    public static Stack<T> Clone3<T>(this Stack<T> original) 
    { 
     var arr = original.ToArray(); 
     Array.Reverse(arr); 
     return new Stack<T>(arr); 
    } 

    public static Stack<T> Clone4<T>(this Stack<T> original) 
    { 
     var arr = new T[original.Count]; 
     original.CopyTo(arr, 0); 
     Array.Reverse(arr); 
     return new Stack<T>(arr); 
    } 
} 

परिणाम हैं:

  • Clone1: 318,3766 एमएस
  • Clone2: 269,2407 एमएस
  • Clone3: 50,6025 एमएस
  • Clone4: 37,5233 एमएस - विजेता

जैसा कि हम देख सकते हैं, का उपयोग करने का दृष्टिकोण CopyTo विधि 8 गुना तेज है और साथ ही कार्यान्वयन बहुत सरल और सीधा है। इसके अलावा, मैं ढेर आकार की एक अधिकतम मूल्य पर एक त्वरित अनुसंधान किया: Clone3 और Clone4 परीक्षण OutOfMemoryException से पहले बड़ा ढेर आकार के लिए काम किया होता है:

  • Clone1: 67,108,765 तत्वों
  • Clone2: 67,108,765 तत्वों
  • Clone3: 134,218,140 तत्वों
  • Clone4: 134,218,140 तत्वों

के लिए Clone1 और Clone2 ऊपर दिए गए परिणामों अतिरिक्त संग्रह है कि स्पष्ट रूप से/परोक्ष परिभाषित और इसलिए प्रभावित स्मृति खपत थे की वजह से छोटे होते हैं। इस प्रकार, क्लोन 3 और क्लोन 4 दृष्टिकोण एक स्टैक इंस्टेंस को तेज़ी से और कम मेमोरी आवंटन के साथ क्लोन करने की अनुमति देते हैं। आप प्रतिबिंब का उपयोग कर भी बेहतर परिणाम हासिल कर सकते हैं, लेकिन यह एक अलग कहानी :)

पूरा कार्यक्रम सूची पाया जा सकता है here है।

संबंधित मुद्दे