是否有内置的方法来限制System.Collection.Generics.Stack的深度?因此,如果您处于最大容量,推送一个新元素将删除堆栈的底部?
我知道我可以通过转换为数组并重建堆栈来实现它,但我认为它上面可能已有一种方法。
编辑:我写了一个扩展方法: public static void Trim<T> (this Stack<T> stack, int trimCount)
{
if (stack.Count <= trimCount)
return;
stack = new
Stack<T>
(
stack
.ToArray()
.Take(trimCount)
);
}
因此,它在修剪时返回一个新的堆栈,但不是函数式方式的不变性=)
原因是我在堆栈中存储应用程序的撤消步骤,我只想存储有限的步骤。
答案 0 :(得分:17)
您正在寻找的是辍学堆。 AFAIK,BCL不包含一个,尽管它们很容易实现。通常,撤消和重做功能依赖于此类数据结构。
它们基本上是一个数组,当你进入堆栈时,堆栈的“顶部”会在数组周围移动。最后,当堆栈已满时,顶部将回到开头并替换堆栈的“底部”。
谷歌没有提供太多信息。这是我能找到的最好的:
(警告PDF) http://courses.cs.vt.edu/~cs2704/spring04/projects/DropOutStack.pdf
这是一些锅炉板代码,以帮助您入门。我会让你填写其余的(完整性检查,计数,索引等)
class DropOutStack<T>
{
private T[] items;
private int top = 0;
public DropOutStack(int capacity)
{
items = new T[capacity];
}
public void Push(T item)
{
items[top] = item;
top = (top + 1) % items.Length;
}
public T Pop()
{
top = (items.Length + top - 1) % items.Length;
return items[top];
}
}
答案 1 :(得分:3)
您实际上正在查看类似于循环列表实现的内容。 PIEBALDconsult在CodeProject上完成了LimitedQueue实现。它与您的要求类似。您只需要像作者所做的那样包装Stack而不是Queue。此外,作者还实现了索引器,如果您需要访问除顶部堆栈之外的任何其他内容(可能显示撤消列表),这将非常方便。
编辑:作者的实现也会在最后一个事件(首先,取决于它是队列还是堆栈)被删除时引发一个事件,这样你就可以知道什么时候被扔掉了。
答案 2 :(得分:2)
对于其他任何人,在尝试限制其撤消/重做堆栈大小时遇到此问题,这里是最佳解决方案(使用LinkedList):
答案 3 :(得分:1)
我看不出办法。您可以从Stack<T>
继承,但似乎没有任何有用的覆盖。
简单(如果有点乏味)的方式是将Stack<T>
包裹在你自己的地方,比如LimitedStack<T>
。然后实现您想要的方法并传递给内部Stack<T>
,同时在Push
方法中包含您的限制逻辑以及您需要的任何其他方法。
编写所有传递成员是一件痛苦的事情,特别是如果你实现了与Stack<T>
相同的所有接口......但另一方面,你只需要做一次然后它就是完成。
答案 4 :(得分:1)
我相信你正在寻找(可能已修改的)dequeue - 允许从任何一端进行访问的数据结构。
答案 5 :(得分:0)
Greg Dean => dropout stack
提供的解决方案非常好,但是我认为主要的问题是关于在堆栈溢出时移除堆栈底部
但是提供的解决方案只是在堆满后替换掉堆中的最后一项,所以您不会获得真实的历史记录,
但是要获得真实的历史记录,您需要在列表达到特定容量后才移动列表,但这是一项庞大的操作,
因此,我认为对此的最佳解决方案是链接列表
这是我解决问题的方法
public class HistoryStack<T>
{
private LinkedList<T> items = new LinkedList<T>();
public List<T> Items => items.ToList();
public int Capacity { get;}
public HistoryStack(int capacity)
{
Capacity = capacity;
}
public void Push(T item)
{
// full
if (items.Count == Capacity)
{
// we should remove first, because some times, if we exceeded the size of the internal array
// the system will allocate new array.
items.RemoveFirst();
items.AddLast(item);
}
else
{
items.AddLast(new LinkedListNode<T>(item));
}
}
public T Pop()
{
if (items.Count == 0)
{
return default;
}
var ls = items.Last;
items.RemoveLast();
return ls == null ? default : ls.Value;
}
}
测试
var hs = new HistoryStack<int>(5);
hs.Push(1);
hs.Push(2);
hs.Push(3);
hs.Push(4);
hs.Push(5);
hs.Push(6);
hs.Push(7);
hs.Push(8);
var ls = hs.Items;
Console.WriteLine(String.Join(",", ls));
Console.WriteLine(hs.Pop());
Console.WriteLine(hs.Pop());
hs.Push(9);
Console.WriteLine(hs.Pop());
Console.WriteLine(hs.Pop());
Console.WriteLine(hs.Pop());
Console.WriteLine(hs.Pop());
Console.WriteLine(hs.Pop()); // empty
Console.WriteLine(hs.Pop()); // empty
结果
4,5,6,7,8
8
7
9
6
5
4
0
0