-2

I require a data structure that has a capacity, but also that allows adding an item from either the front or the back. Each time an item is added, one item must be removed from the opposite end. My first thought was that this sound very similar to a Deque.

Is there an existing data structure that provides this functionality, or do I have to create it myself? If it does exist, does the .Net library have an implementation?

Thanks

  • whats the problem with a deque ? – sashas Feb 11 '15 at 15:25
  • The "common" `List` allows adding on both sides. You could `while(l.Count > cap) l.RemoveAt(...)` – DrKoch Feb 11 '15 at 15:29
  • For a fixed capacity I would try an array. Use a pointer to the virtual start. This way you just update a single value (the virtual start or virtual end). – paparazzo Feb 11 '15 at 15:37
  • Some node-based data structure (e.g. linked list) would be a more logical choice than a contiguous data structure (e.g. array or list) if you're adding/removing from both ends. Otherwise there's going to be a lot of element shifting. – itsme86 Feb 11 '15 at 15:40
  • "Add on both ends" - Deque (not in .Net framework), limited capacity - usually "circular buffer" (not in .Net either)... You'll need to write your own/find other library - some samples may be found in http://stackoverflow.com/questions/1292/limit-size-of-queuet-in-net. – Alexei Levenkov Feb 11 '15 at 15:41
  • 3
    @itsme86 If you if you use a pointer to virtual start you can avoid element shifting. – paparazzo Feb 11 '15 at 15:41
  • @itsme86 for limited capacity array exposed as circular buffer is at least as easy as linked list (possibly for most people linked list is way beyond regular knowledge - so I'd recommend array). – Alexei Levenkov Feb 11 '15 at 15:43
  • 1
    @itsme86 No, a properly implemented pointer would not go negative. – paparazzo Feb 11 '15 at 15:46

3 Answers3

2

I would suggest that you use a LinkedList, which gives you all the functionality you need. There are AddFirst and AddLast methods that let you add items at the front or back, and RemoveFirst and RemoveLast methods that let you remove from the front and back.

And, of course, there's a Count property that tells you how many items are in the list, so you can enforce your capacity requirement.

Jim Mischel
  • 122,159
  • 16
  • 161
  • 305
2

Not tested but something like this I think would work

public class Stack<T>
{
    private T[] arr;
    readonly int m_Size;
    int m_StackPointer = 0;
    public T this[int i]
    {
        get
        {
            if (i >= m_Size)
                throw new IndexOutOfRangeException();
            int pointer = i + m_StackPointer;
            if (pointer >= (m_Size)) pointer -= m_Size;
            return arr[pointer];
        }
    }
    public void AddStart(T addItem)
    {
        m_StackPointer--;
        if (m_StackPointer < 0) m_StackPointer = m_Size - 1;
        arr[m_StackPointer] = addItem;
    }
    public void AddEnd(T addItem)
    {
        arr[m_StackPointer] = addItem;
        m_StackPointer++;
        if (m_StackPointer >= m_Size) m_StackPointer = 0;
    }
    public Stack()
        : this(100)
    { }
    public Stack(int size)
    {
        m_Size = size;
        arr = new T[size];
    }
}
paparazzo
  • 42,665
  • 20
  • 93
  • 158
  • This might be faster than LinkedList as suggested by Jim M. But LinkedList is 0(1) and less code. – paparazzo Feb 11 '15 at 17:37
  • You code (a kind of circular buffer, `Stack` is wrong term here) is O(1) too. – MBo Feb 12 '15 at 05:37
  • @MBo Yes it is O(1) and it might be faster than a LinkedList based solution. – paparazzo Feb 12 '15 at 15:03
  • Yes, this is a Ring Buffer. One of main requirements of the structure is to clearly identify and keep track of a start and an end. I have absolutely no idea how to do this in C#, since raw pointers are not an option. Is sub-scripting really the best choice? –  Feb 13 '15 at 15:24
  • I don't know what you mean by raw pointers and sub-scripting. Did you try this code? You can name the class anything you wish. The question is tagged C#. – paparazzo Feb 13 '15 at 15:54
1

I have decided that the best option is to use an array of T for the backing structure, and have a reference Front and a reference Back to represent the virtual start and end of the structure. I will also store a direction enum that will effectively indicate which direction the structure is facing(whether the last add operation was at the Front or the Back or a default if no add operations have been performed). This way, I can also implement an indexer with O(1) complexity, rather than iterating the collection.

Thanks for all of the responses. For some reason, I thought that I would need to move the data around in the backing structure. I didn't realize that this option is possible in C#.