c#克隆一个堆栈

时间:2011-09-12 17:03:01

标签: c# .net stack clone

我的代码中有很少的堆栈用于跟踪我的逻辑位置。在某些时候我需要复制堆栈,但我似乎无法以保留订单的方式克隆它们。我只需要浅层复制(引用,而不是对象)。

这样做的正确方法是什么?或者我应该使用其他类型的堆栈?

注意:我看过这篇文章Stack Clone Problem: .NET Bug or Expected Behaviour?,但不知道如何为Stack类设置克隆方法。

注意#2:我使用System.Collection.Generic.Stack

4 个答案:

答案 0 :(得分:25)

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>的{​​{1}}实现进行迭代时,它将会从堆栈中反复弹出项目,从而按照您希望它们进入新堆栈的顺序将它们提供给您。因此,执行此过程两次将导致堆栈处于正确的顺序。

可替换地:

Stack<T>

同样,我们必须以相反的顺序从堆栈中迭代的输出开始堆栈。

我怀疑这两种方法之间存在性能差异。

答案 1 :(得分:8)

这是一种简单的方法,使用LINQ:

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

您可以创建一个扩展方法,以便更轻松:

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

用法:

var clone = originalStack.Clone();

答案 2 :(得分:7)

对于那些照顾性能的人来说。还有其他几种方法可以在不损失性能的情况下迭代原始堆栈成员:

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 ms
  • Clone2:269,2407 ms
  • 克隆3:50,6025毫秒
  • 克隆4:37,5233毫秒 - 获胜者

正如我们所看到的,使用 CopyTo 方法的方法快8倍,同时实现非常简单明了。此外,我对堆栈大小的最大值进行了快速研究: Clone3 Clone4 测试在 OutOfMemoryException 发生之前适用于更大的堆栈大小:< / p>

  • 克隆1:67108765元素
  • 克隆2:67108765元素
  • 克隆3:134218140元素
  • 克隆4:134218140元素

Clone1 Clone2 的上述结果较小,原因是显式/隐式定义了额外的集合,因此影响了内存消耗。因此, Clone3 Clone4 方法允许更快地克隆堆栈实例并减少内存分配。你可以使用Reflection获得更好的结果,但它是一个不同的故事:)

可以找到完整的计划列表here

答案 3 :(得分:0)

如果您不需要实际的Stack`1,但只想要一个现有Stack`1的快速副本,您可以按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
相关问题