堆栈的替代品

时间:2011-02-15 11:45:45

标签: c# .net data-structures stack circular-buffer

我使用C#在.Net环境中工作。我需要一些替代堆栈数据结构。某种绑定堆栈。集合中元素的数量不应超过某个固定的指定数量。并且,如果实现了该数字并且推送了新元素,则必须删除大多数旧元素。我需要这个来存储撤消/重做策略的命令。

5 个答案:

答案 0 :(得分:7)

circular buffer应该做的工作;很容易包装列表或数组,但没有内置在AFAIK中。

答案 1 :(得分:5)

答案 2 :(得分:2)

.Net在收藏类型上相当缺乏。你会找到一个集合库here。使用 CircularQueue

答案 3 :(得分:2)

这是具有约束容量的堆栈的实现。 达到给定容量后,超出容量的堆栈底部项目将被丢弃。可以迭代包含的对象并将索引设置为特定位置(如倒带),以便在将新项目推送到堆栈时立即丢弃多个条目。

这是一个自己的实现,如果您需要返回历史记录并再次转发(内置),则会阻止您处理多个列表。

public class DiscardingStack<TObject> : IEnumerable<TObject>
{
    private readonly int capacity;

    private readonly List<TObject> items;

    private int index = -1;

    public DiscardingStack(int capacity)
    {
        this.capacity = capacity;
        items = new List<TObject>(capacity);
    }

    public DiscardingStack(int capacity, IEnumerable<TObject> collection)
        : this(capacity)
    {
        foreach (var o in collection)
        {
            Push(o);
        }
    }

    public DiscardingStack(ICollection<TObject> collection)
        : this(collection.Count, collection)
    {
    }

    public void Clear()
    {
        if (items.Count >= 0)
        {
            items.Clear();
            index = items.Count - 1;
        }
    }

    public int Index
    {
        get { return index; }
        set
        {
            if (index >= 0 && index < items.Count)
            {
                index = value;
            }
            else throw new InvalidOperationException();
        }
    }

    public int Count
    {
        get { return items.Count; }
    }

    public TObject Current
    {
        get { return items[index]; }
        set { index = items.IndexOf(value); }
    }

    public int Capacity
    {
        get { return capacity; }
    }

    public TObject Pop()
    {
        if (items.Count <= 0)
            throw new InvalidOperationException();

        var i = items.Count - 1;
        var removed = items[i];
        items.RemoveAt(i);

        if (index > i)
            index = i;

        return removed;
    }

    public void Push(TObject item)
    {
        if (index == capacity - 1)
        {
            items.RemoveAt(0);
            index--;
        }
        else if (index < items.Count - 1)
        {
            var removeAt = index + 1;
            var removeCount = items.Count - removeAt;
            items.RemoveRange(removeAt, removeCount);
        }

        items.Add(item);

        index = items.Count - 1;
    }

    public TObject Peek()
    {
        return items[items.Count-1];
    }

    public TObject this[int i]
    {
        get { return items[i]; }
    }

    public IEnumerator<TObject> GetEnumerator()
    {
        return items.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

无论如何,如果列表很大(避免复制),应该使用LinkedList(如上所述)构建一个在达到最大容量时丢弃元素的堆栈。因此,在这种情况下,LinkedList的想法可能会更好,而不是在缓冲区最大值为高值时包装List。

我还建议将Push(),Pop()等打包到一个接口(例如IStack)中。遗憾的是,.Net(afaik)中没有预定义的IStack接口。

答案 4 :(得分:1)

Framework中没有内置类。 (我们不希望自动删除数据)。但您可以扩展 Stack类和覆盖推/弹以及其他方法以满足您的需求。