You're using the stack backwards. Not only that, but it's not a true stack. (Which is fine, we'll talk about that now.)
A true stack cannot have elements directly modified. In a stack there's no sense of an "index", elements go in the top and come out the top. With that said, the easiest way to fix that is to rename this from StackList
to FiloList
. (Now the name is more meaningful - first-in-last-out list.)
It's far more performant to insert items at the end and then remove them from the end.
public T Pop()
{
if (_stackList.Count == 0)
{
throw new InvalidOperationException("The stack is empty");
}
T value = _stackList[_stackList.Count - 1];
_stackList.RemoveAt(_stackList.Count - 1);
return value;
}
public void Push(T item)
{
_stackList.Add(item);
}
public T Peek()
{
if (_stackList.Count == 0)
{
throw new InvalidOperationException("The stack is empty");
}
return _stackList[_stackList.Count];
}
We also used RemoveAt
as Remove
may not guarantee what we want.
Now, I can see why you wrote it the way you did, but we'll fix that.
You can modify this[int index]
and IndexOf(T item)
to work relative to the end of the stack.
public T this[int index]
{
get { return _stackList[_stackList.Count - 1 - index]; }
set { _stackList[_stackList.Count - 1 - index] = value; }
}
public int IndexOf(T item)
{
return _stackList.Count - 1 - _stackList.IndexOf(item);
}
You should then write your own IEnumerator
which enumerates it backwards.
In the end we'll have:
public class StackList<T> : IEnumerable<T>
{
private readonly List<T> _stackList = new List<T>();
public T Pop()
{
if (_stackList.Count == 0)
{
throw new InvalidOperationException("The stack is empty");
}
T value = _stackList[_stackList.Count - 1];
_stackList.RemoveAt(_stackList.Count - 1);
return value;
}
public void Push(T item)
{
_stackList.Add(item);
}
public T Peek()
{
if (_stackList.Count == 0)
{
throw new InvalidOperationException("The stack is empty");
}
return _stackList[_stackList.Count];
}
public IEnumerator<T> GetEnumerator()
{
return _stackList.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public T this[int index]
{
get { return _stackList[_stackList.Count - 1 - index]; }
set { _stackList[_stackList.Count - 1 - index] = value; }
}
public int Count
{
get { return _stackList.Count; }
}
public void Clear()
{
_stackList.Clear();
}
public bool Contains(T item)
{
return _stackList.Contains(item);
}
public int IndexOf(T item)
{
return _stackList.Count - 1 - _stackList.IndexOf(item);
}
}
And I've tested this with yours:
Pushing 10 items to top of stack.
Pushing another item on top of stack.
Modifying second to last item to new value.
Index of item just modified: 9
Popping 10 items from top of stack.
Index: 0, value: 10
Index: 1, value: 9
Index: 2, value: 8
Index: 3, value: 7
Index: 4, value: 6
Index: 5, value: 5
Index: 6, value: 4
Index: 7, value: 3
Index: 8, value: 2
Index: 9, value: 100
Printing items left in stack.
Value left in stack: 0
And mine:
Pushing 10 items to top of stack.
Pushing another item on top of stack.
Modifying second to last item to new value.
Index of item just modified: 9
Popping 10 items from top of stack.
Index: 0, value: 10
Index: 1, value: 9
Index: 2, value: 8
Index: 3, value: 7
Index: 4, value: 6
Index: 5, value: 5
Index: 6, value: 4
Index: 7, value: 3
Index: 8, value: 2
Index: 9, value: 100
Printing items left in stack.
Value left in stack: 0
The only thing left to do is rewrite it to use a custom IEnumerator
, then you'll be all set.
Queue
in C# that is 2x the speed of the Microsoft supplied version just this morning. \$\endgroup\$