我需要什么数据结构或如何实现“类似LIFO”的队列?

时间:2014-01-27 11:17:04

标签: c# .net generics data-structures

我正在寻找一个行为如下的数据结构:

  1. 最后,先出
  2. 迭代后,第一项是最后一项(LCFS - 最后来,先送达)
  3. 达到最大容量时,需要删除“最旧”项目
  4. 听起来Queue可以解决问题,但该结构是FIFO。听起来我需要一个类似LIFO的队列。

    我应该使用什么想法?

7 个答案:

答案 0 :(得分:2)

基础.NET库中有Stack,但这没有最后的要求。而且我相信没有像这样的现有结构,所以你必须自己实现它。

但那应该不是问题。只需创建一个链接列表,您可以在其中添加和删除一侧,并在项目数量超过给定大小时从其他位置删除。您可以通过使用带有开始指针的数组来优化它,但是您必须定期重新排列数组,这样就不会耗尽空间。循环版本实际上可以比重新安排更好。

我使用循环版本做了一些快速黑客攻击。我相信你可以自己添加界面。

public class DroppingStack<T> : IEnumerable<T>
{
    T[] array;
    int cap;
    int begin;
    int end;
    public DroppingStack (int capacity)
    {
        cap = capacity+1;
        array = new T[cap];
        begin = 0;
        end = 0;
    }

    public T pop()
    {
        if (begin == end) throw new Exception("No item");
        begin--;
        if (begin < 0)
            begin += cap;
        return array[begin];
    }

    public void push(T value)
    {
        array[begin] = value;
        begin = (begin+1)%cap;
        if (begin == end)
            end = (end + 1) % cap;
    }

    public IEnumerator<T> GetEnumerator()
    {
        int i = begin-1;
        while (i != end-1)
        {
            yield return array[i];
            i--;
            if (i < 0)
                i += cap;
        }
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}

答案 1 :(得分:1)

它就像一个具有规定容量的循环LIFO。

答案 2 :(得分:1)

.Net有一个名为Stack<T>的LIFO“队列”结构,虽然这不符合你的第三个约束(例如大小限制)。通过遏制来实现这一点并不太难。

但是......如果你想丢弃堆栈中最旧的项目,最好使用循环缓冲区。这可以通过以下方式实现:

class OverflowingStack<T>
{
    private T[] items;
    private int currentIndex;
    private int count;

    public OverflowingStack(int size)
    {
        this.items = new T[size];
        this.currentIndex = 0;
        this.count = 0;
    }
    public void Push(T item)
    {
        items[currentIndex] = item;
        currentIndex++;
        currentIndex %= items.Length;
        count++;
        count = count > items.Length ? items.Length : count;

    }
    public T Pop()
    {
        if (count == 0) throw new Exception("stack is empty");
        currentIndex--;
        while (currentIndex < 0) {currentIndex += items.Length;}
        count--;
        return items[currentIndex];
    }
}

我会将其他接口实现留给您,但您明白了。

答案 3 :(得分:1)

示例性的后进先出数据结构是Stack。这将满足第一和第二要求。但是,这不符合第三个要求。对于该要求,您可能最好使用Queue,尽管默认情况下是FIFO数据类型。我不相信现有的数据结构符合您的要求,这意味着您必须自己构建它。

答案 4 :(得分:1)

像这样的东西,随意使用它。 IEnumerable的实现是读者的练习(如果他需要的话):

    class CyclicStack<T>
    {
        private T[] stack;
        private int capacity;
        private int curIndex = 0;

        public  int Count { get; private set; }
        public CyclicStack(int capacity)
        {
            this.capacity = capacity;
            stack = new T[capacity];
            this.Count = 0;
        }
        public T this[int index]
        {
           get
           {
               if (index >= capacity)
                   throw new Exception("Index is out of bounds");
               return this.stack[(curIndex + index) % capacity];
           }
        }
        public void Push(T item)
        {
            curIndex = (curIndex + capacity - 1) % capacity;
            stack[curIndex] = item;
            this.Count++;
        }
        public T Pop()
        {
            if (this.Count == 0)
                throw new Exception("Collection is empty");
            int oldIndex = curIndex;
            curIndex = (curIndex + capacity + 1) % capacity;
            this.Count--;
            return stack[oldIndex];
        }
    }

答案 5 :(得分:0)

我建议使用Stack

MSDN Stack Class

答案 6 :(得分:0)

使用LinkedList<T>

public class LifoBuffer<T> : LinkedList<T>
{
    private int capacity;

    public LifoBuffer(int capacity)
    {
        this.capacity = capacity;   
    }

    public void Add(T item)
    {
        if (Count == capacity) RemoveLast();
        AddFirst(item);
    }
}

void Main()
{
    var lifoBuffer = new LifoBuffer<int>(3);
    lifoBuffer.Add(1);
    lifoBuffer.Add(2);
    lifoBuffer.Add(3);
    lifoBuffer.Add(4);
    lifoBuffer.Add(5);
    foreach (var item in lifoBuffer) Console.WriteLine(item); // outputs: 5, 4, 3
}