C# 克隆一个堆栈
在我的代码中,我很少使用堆栈来跟踪我的逻辑位置。在某些时候,我需要复制堆栈,但我似乎不能以这样的方式克隆它们,以保持顺序。我只需要浅复制(引用,而不是对象) 正确的方法是什么?或者我应该使用其他类型的堆栈 注意:我看到了这篇文章,但不确定如何为Stack类设置clone方法 注意#2:我使用System.Collection.Generic.StackC# 克隆一个堆栈,c#,.net,stack,clone,C#,.net,Stack,Clone,在我的代码中,我很少使用堆栈来跟踪我的逻辑位置。在某些时候,我需要复制堆栈,但我似乎不能以这样的方式克隆它们,以保持顺序。我只需要浅复制(引用,而不是对象) 正确的方法是什么?或者我应该使用其他类型的堆栈 注意:我看到了这篇文章,但不确定如何为Stack类设置clone方法 注意#2:我使用System.Collection.Generic.Stackvar clonedStack=newstack(newstack(oldStack)); var clonedStack = new Stack
var clonedStack=newstack(newstack(oldStack));
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));
}
公共静态堆栈克隆(此堆栈){
Contract.Requires(stack!=null);
返回新堆栈(新堆栈(堆栈));
}
这是必要的,因为我们在这里使用的堆栈
构造函数是,当然,当您迭代堆栈
的IEnumerable
实现时,它将重复从堆栈中弹出项,从而按照您希望它们进入新堆栈的相反顺序将它们提供给您。因此,两次执行此过程将导致堆栈的顺序正确
或者:
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 clonedStack=新堆栈(oldStack.Reverse());
公共静态堆栈克隆(此堆栈){
Contract.Requires(stack!=null);
返回新堆栈(Stack.Reverse());
}
同样,我们必须按照与迭代堆栈的输出相反的顺序遍历堆栈
我怀疑这两种方法之间是否存在性能差异。这里有一种简单的方法,使用LINQ:
var clone = new Stack<ElementType>(originalStack.Reverse());
如果您不需要实际的
Stack`1
,只需要一个现有Stack`1
的快速副本,可以按照Pop
返回的相同顺序运行,另一个选项是将Stack`1
复制到队列`1
中。然后,这些元素将按照从原始堆栈`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());
}
}
使用系统;
使用System.Collections.Generic;
课堂测试
{
静态void Main()
{
var stack=新堆栈();
stack.Push(“先推,后弹出”);
堆叠。推动(“中间”);
stack.Push(“最后推,先弹出”);
var quickCopy=新队列(堆栈);
Console.WriteLine(“堆栈:”);
而(stack.Count>0)
Console.WriteLine(“+stack.Pop());
Console.WriteLine();
控制台写入线(“队列:”);
而(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
堆栈:
最后推,先弹出
在中间
先推,后弹出
队列:
最后推,先弹出
在中间
先推,后弹出
对于那些关注性能的人。。还有一些其他方法可以在不损失性能的情况下迭代原始堆栈成员:
public T[] Stack<T>.ToArray();
public void Stack<T>.CopyTo(T[] array, int arrayIndex);
public T[]Stack.ToArray();
public void Stack.CopyTo(T[]数组,int-arrayIndex);
我编写了一个粗略的程序(链接将在文章末尾提供)来衡量性能,并为已经建议的实现添加了两个测试(参见Clone1和Clone2),以及两个测试ToArray和CopyTo方法(参见Clone3和Clone4,它们都使用更有效的数组。反向方法)
公共静态类堆栈扩展
{
公共静态堆栈克隆1(此堆栈原始)
{
返回新堆栈(新堆栈(原始));
}
公共静态堆栈克隆2(此堆栈原始)
{
返回新堆栈(original.Reverse());
}
公共静态堆栈克隆3(此堆栈原始)
{
var arr=original.ToArray();
阵列。反向(arr);
返回新堆栈(arr);
}
公共静态堆栈克隆4(此堆栈原始)
{
var arr=新的T[原始计数];
原件。复印件(arr,0);
阵列。反向(arr);
返回新堆栈(arr);
}
}
结果是:
- 克隆1:3183766毫秒
- 克隆2:2692407毫秒
- 克隆3:506025毫秒
- 克隆4:375233毫秒-获胜者
正如我们所看到的,使用CopyTo方法的方法速度快了8倍,同时实现非常简单和直接。此外,我还快速研究了堆栈大小的最大值:在OutOfMemoryException发生之前,Clone3和Clone4测试适用于更大的堆栈大小:
- 克隆1:67108765个元素
- 克隆2:67108765个元素
- 克隆3:134218140个元素
- 克隆4:134218140个元素
由于显式/隐式定义了额外的集合,因此Clone1和Clone2的上述结果较小,从而影响了内存消耗。因此,Clone3和Clone4方法允许更快地克隆堆栈实例,并且使用更少的内存分配。使用反射可以获得更好的结果,但情况不同:)
可以找到完整的程序列表。遗憾的是,奇怪的是,这并没有保留顺序:((我假设堆栈的双重初始化是打字错误还是一个技巧?)@Angrius:它确实保留了顺序。双重实例化是一个导致顺序被保留的技巧。@Angrius:双重初始化”是必需的,因为每一个都会反转顺序。如果反转两次,则会得到原始顺序。@Angrius:另外,它不保留顺序也不奇怪。请参阅我对其发生原因的解释。IEnumerable
forStack
的实现非常有意义;如果IEnumerable的实现e> 对于Stack
来说,除了重复弹出和输出之外,我什么都做了。对于Stack(IEnumerable source)
来说,构造函数非常有意义;如果Stack
的构造函数除了从源代码中拉出和推送之外,什么都做了,我会感到困惑。这一点都不奇怪
Stack:
pushed last, pop first
in the middle
pushed first, pop last
Queue:
pushed last, pop first
in the middle
pushed first, pop last
public T[] Stack<T>.ToArray();
public void Stack<T>.CopyTo(T[] array, int arrayIndex);
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);
}
}