Ограничение размера очереди <T> в .NET?

голоса
50

У меня есть объект Queue <T>, который я инициализируется мощностью 2, но очевидно, что это просто емкость и продолжает расширяться, как добавить элементы. Есть ли уже объект, который автоматически dequeues элемента, когда достигнут предел, или является лучшим решением создать свой собственный унаследованный класс?

Задан 04/08/2008 в 15:47
источник пользователем
На других языках...                            


7 ответов

голоса
3

Почему бы вам не просто использовать массив с размером 2? Очередь должна иметь возможность динамически увеличиваться и уменьшаться.

Или создать класс - оболочку вокруг экземпляра Queue<T>экземпляра и каждый раз , когда один ставит в очередь <T>объекта, проверьте размер очереди. Если больше чем 2, из очереди первого элемента.

Ответил 04/08/2008 в 15:52
источник пользователем

голоса
5

Вы должны создать свой собственный класс, ringbuffer, вероятно, соответствует вашим потребностям.

Структуры данных в .NET, что позволяет указать емкость, для массива, за исключением, использует это, чтобы построить внутреннюю структуру данных, используемую для хранения внутренних данных.

Например, для списка, емкость используется для размера внутреннего массива. Когда вы начинаете добавлять элементы в список, он начнет заполнение этого массива от индекса 0 и до, и когда она достигает вашу способность, повышает способность к новой более высокой мощности, и продолжает наполнять ее.

Ответил 04/08/2008 в 15:56
источник пользователем

голоса
32

Я постучал базовую версию того, что я ищу, это не идеально, но это будет делать эту работу, пока что-то лучше не приходит.

public class LimitedQueue<T> : Queue<T>
{
    public int Limit { get; set; }

    public LimitedQueue(int limit) : base(limit)
    {
        Limit = limit;
    }

    public new void Enqueue(T item)
    {
        while (Count >= Limit)
        {
            Dequeue();
        }
        base.Enqueue(item);
    }
}
Ответил 04/08/2008 в 15:57
источник пользователем

голоса
17

Я рекомендовал бы , чтобы вы подтяните C5 Library . В отличие от SCG (System.Collections.Generic), С5 запрограммирован на интерфейс и предназначена для подклассы. Большинство общественных методы являются виртуальными и ни один из классов не уплотнены. Таким образом, вы не должны использовать это неприглядное «новый» ключевое слово , которое не будет срабатывать , если ваш LimitedQueue<T>отливали к SCG.Queue<T>. С C5 и использование близко к тому же код , как вы были раньше, вы могли бы извлечь из CircularQueue<T>. CircularQueue<T>Фактически реализует как стек и очередь, так что вы можете получить оба варианта с лимитом почти бесплатно. Я переписать его ниже с некоторыми 3,5 конструкций:

using C5;

public class LimitedQueue<T> : CircularQueue<T>
{
    public int Limit { get; set; }

    public LimitedQueue(int limit) : base(limit)
    {
        this.Limit = limit;
    }

    public override void Push(T item)
    {
        CheckLimit(false);
        base.Push(item);
    }

    public override void Enqueue(T item)
    {
        CheckLimit(true);
        base.Enqueue(item);
    }

    protected virtual void CheckLimit(bool enqueue)
    {
        while (this.Count >= this.Limit)
        {
            if (enqueue)
            {
                this.Dequeue();
            }
            else
            {
                this.Pop();
            }
        }
    }
}

Я думаю, что этот код должен делать то, что вы искали.

Ответил 24/10/2008 в 14:51
источник пользователем

голоса
3

Ну, я надеюсь, что этот класс поможет Вам:
Внутренне круговой FIFO буфера используется Queue <T> с заданным размером. После того , как размер буфера будет достигнут, он будет заменяет старые детали с новыми.

Примечание: Вы не можете удалять элементы в случайном порядке. Я установил метод Remove (Т элемента), чтобы вернуться ложным. если Вы хотите, Вы можете изменить, чтобы удалить элементы в случайном порядке

public class CircularFIFO<T> : ICollection<T> , IDisposable
{
    public Queue<T> CircularBuffer;

    /// <summary>
    /// The default initial capacity.
    /// </summary>
    private int capacity = 32;

    /// <summary>
    /// Gets the actual capacity of the FIFO.
    /// </summary>
    public int Capacity
    {
        get { return capacity; }          
    }

    /// <summary>
    ///  Initialize a new instance of FIFO class that is empty and has the default initial capacity.
    /// </summary>
    public CircularFIFO()
    {            
        CircularBuffer = new Queue<T>();
    }

    /// <summary>
    /// Initialize a new instance of FIFO class that is empty and has the specified initial capacity.
    /// </summary>
    /// <param name="size"> Initial capacity of the FIFO. </param>
    public CircularFIFO(int size)
    {
        capacity = size;
        CircularBuffer = new Queue<T>(capacity);
    }

    /// <summary>
    /// Adds an item to the end of the FIFO.
    /// </summary>
    /// <param name="item"> The item to add to the end of the FIFO. </param>
    public void Add(T item)
    {
        if (this.Count >= this.Capacity)
            Remove();

        CircularBuffer.Enqueue(item);
    }

    /// <summary>
    /// Adds array of items to the end of the FIFO.
    /// </summary>
    /// <param name="item"> The array of items to add to the end of the FIFO. </param>
     public void Add(T[] item)
    { 
        int enqueuedSize = 0;
        int remainEnqueueSize = this.Capacity - this.Count;

        for (; (enqueuedSize < item.Length && enqueuedSize < remainEnqueueSize); enqueuedSize++)
            CircularBuffer.Enqueue(item[enqueuedSize]);

        if ((item.Length - enqueuedSize) != 0)
        {
            Remove((item.Length - enqueuedSize));//remaining item size

            for (; enqueuedSize < item.Length; enqueuedSize++)
                CircularBuffer.Enqueue(item[enqueuedSize]);
        }           
    }

    /// <summary>
    /// Removes and Returns an item from the FIFO.
    /// </summary>
    /// <returns> Item removed. </returns>
    public T Remove()
    {
        T removedItem = CircularBuffer.Peek();
        CircularBuffer.Dequeue();

        return removedItem;
    }

    /// <summary>
    /// Removes and Returns the array of items form the FIFO.
    /// </summary>
    /// <param name="size"> The size of item to be removed from the FIFO. </param>
    /// <returns> Removed array of items </returns>
    public T[] Remove(int size)
    {
        if (size > CircularBuffer.Count)
            size = CircularBuffer.Count;

        T[] removedItems = new T[size];

        for (int i = 0; i < size; i++)
        {
            removedItems[i] = CircularBuffer.Peek();
            CircularBuffer.Dequeue();
        }

        return removedItems;
    }

    /// <summary>
    /// Returns the item at the beginning of the FIFO with out removing it.
    /// </summary>
    /// <returns> Item Peeked. </returns>
    public T Peek()
    {
        return CircularBuffer.Peek();
    }

    /// <summary>
    /// Returns the array of item at the beginning of the FIFO with out removing it.
    /// </summary>
    /// <param name="size"> The size of the array items. </param>
    /// <returns> Array of peeked items. </returns>
    public T[] Peek(int size)
    {
        T[] arrayItems = new T[CircularBuffer.Count];
        CircularBuffer.CopyTo(arrayItems, 0);

        if (size > CircularBuffer.Count)
            size = CircularBuffer.Count;

        T[] peekedItems = new T[size];

        Array.Copy(arrayItems, 0, peekedItems, 0, size);

        return peekedItems;
    }

    /// <summary>
    /// Gets the actual number of items presented in the FIFO.
    /// </summary>
    public int Count
    {
        get
        {
            return CircularBuffer.Count;
        }
    }

    /// <summary>
    /// Removes all the contents of the FIFO.
    /// </summary>
    public void Clear()
    {
        CircularBuffer.Clear();
    }

    /// <summary>
    /// Resets and Initialize the instance of FIFO class that is empty and has the default initial capacity.
    /// </summary>
    public void Reset()
    {
        Dispose();
        CircularBuffer = new Queue<T>(capacity);
    }

    #region ICollection<T> Members

    /// <summary>
    /// Determines whether an element is in the FIFO.
    /// </summary>
    /// <param name="item"> The item to locate in the FIFO. </param>
    /// <returns></returns>
    public bool Contains(T item)
    {
        return CircularBuffer.Contains(item);
    }

    /// <summary>
    /// Copies the FIFO elements to an existing one-dimensional array. 
    /// </summary>
    /// <param name="array"> The one-dimensional array that have at list a size of the FIFO </param>
    /// <param name="arrayIndex"></param>
    public void CopyTo(T[] array, int arrayIndex)
    {
        if (array.Length >= CircularBuffer.Count)
            CircularBuffer.CopyTo(array, 0);           
    }

    public bool IsReadOnly
    {
        get { return false; }
    }

    public bool Remove(T item)
    {
        return false; 
    }

    #endregion

    #region IEnumerable<T> Members

    public IEnumerator<T> GetEnumerator()
    {
       return CircularBuffer.GetEnumerator();
    }

    #endregion

    #region IEnumerable Members

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

    #endregion

    #region IDisposable Members

    /// <summary>
    /// Releases all the resource used by the FIFO.
    /// </summary>
    public void Dispose()
    {          
        CircularBuffer.Clear();
        CircularBuffer = null;
        GC.Collect();
    }

    #endregion
}
Ответил 15/11/2011 в 13:40
источник пользователем

голоса
1

Если это никакой пользы никому, я сделал LimitedStack<T>.

public class LimitedStack<T>
{
    public readonly int Limit;
    private readonly List<T> _stack;

    public LimitedStack(int limit = 32)
    {
        Limit = limit;
        _stack = new List<T>(limit);
    }

    public void Push(T item)
    {
        if (_stack.Count == Limit) _stack.RemoveAt(0);
        _stack.Add(item);
    }

    public T Peek()
    {
        return _stack[_stack.Count - 1];
    }

    public void Pop()
    {
        _stack.RemoveAt(_stack.Count - 1);
    }

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

Она удаляет самый старый элемент (в нижней части стека), когда он становится слишком большим.

(Этот вопрос был главным результатом Google для «# предельного размера стека C»)

Ответил 15/01/2012 в 06:28
источник пользователем

голоса
0

Параллельное решение

public class LimitedConcurrentQueue<ELEMENT> : ConcurrentQueue<ELEMENT>
{
    public readonly int Limit;

    public LimitedConcurrentQueue(int limit)
    {
        Limit = limit;
    }

    public new void Enqueue(ELEMENT element)
    {
        base.Enqueue(element);
        if (Count > Limit)
        {
            TryDequeue(out ELEMENT discard);
        }
    }
}

Примечание: Так как Enqueueэлементы управления добавлением элементов, и делает это по одному, нет необходимости выполнять whileдля TryDequeue.

Ответил 09/05/2018 в 20:39
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more