2011-02-15 14 views
7

Estoy trabajando en el entorno .Net usando C#. Necesito alguna alternativa para la estructura de datos Stack. Algún tipo de pila atada. La cantidad de elementos en la colección no debe exceder un número fijo determinado. Y, si se logra ese número y se empuja un nuevo elemento, debe eliminarse el elemento más antiguo. Necesito esto para almacenar comandos para las estrategias Deshacer/Rehacer.Alternativa para la pila

Respuesta

7

A circular buffer debería hacer el trabajo; lo suficientemente fácil como para envolver una lista o matriz, pero nada incorporado en AFAIK.

+1

hey mark has cruzado 200K !! oh, quise votar el último punto ... Felicidades .. –

+2

Gracias. Encontré la implementación gratuita del búfer circular aquí: bufferhttp: //circularbuffer.codeplex.com/ – Peter17

1

No hay ninguna clase de orden interna para esto en marco. (no esperamos eliminar datos automáticamente). Pero puede muy bien Extender la clase Stack y Anular push/pop y otros métodos para satisfacer sus necesidades.

+0

No es una buena idea porque no son virtuales. Podría abatir y llamar a los viejos Métodos. – Beachwalker

+0

Cuando lo lanzas Obviamente significa que quieres la implementación base ... y eso es lo que debería ser ... –

+0

El problema es que no hay una interfaz IStack . Es "más seguro" incluir la lista como miembro en este caso (composición en lugar de herencia). De lo contrario, la herencia podría generar resultados inesperados. ¿Qué sucede si alguien llama a Push() del System.Collections.Generics.Stack scheduling y su nueva implementación pública de Push() debe desencadenar un evento ... el evento NO se activa y los oyentes no obtienen la información sobre la pila cambio (por ejemplo, al mostrar la cantidad de elementos). – Beachwalker

2

.Net es bastante deficiente en el tipo de colecciones. Encontrará una biblioteca de colecciones here. Use CircularQueue.

+0

Gracias. La biblioteca de colecciones será útil. Ahora sé dónde buscar cuando necesito una colección específica. – Peter17

2

Esta es una implementación de una pila con una capacidad restringida. Después de alcanzar la capacidad dada, los artículos del fondo de la pila más allá de la capacidad se descartan. Es posible iterar a través de los objetos contenidos y establecer el índice en una posición específica (como un rebobinado) para descartar múltiples entradas a la vez cuando se empuja un nuevo elemento a la pila.

Esta es una implementación propia con algunos extras que le impide manejar más de una lista si necesita volver al historial y reenviarla (está incorporada).

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(); 
    } 
} 

De todos modos, la construcción de una pila que descarta los elementos cuando se alcanza debe ser implementado usando un LinkedList la capacidad máxima (como se sugirió anteriormente) si la lista es enorme (evita la copia). Entonces, la idea LinkedList podría ser mejor en ese caso en lugar de envolver una lista si el máximo del buffer es de alto valor.

También recomendaría empaquetar Push(), Pop(), etc. en una interfaz (por ejemplo, IStack). Lamentablemente, no hay una interfaz IStack predefinida en .Net (afaik).