2

我发现不止一种情况,泛型集合需要在某个时间点被视为一个列表,而在另一个时间点被视为一个堆栈或队列。对于我目前正在开发的应用程序,使用三个单独的对象是没有意义的。

我能想到的最简单的解决方案是在标准 List 上实现 Queue/Dequeue/Push/Pop/Peek 函数。此外(不包括在下面的代码中),接口约束应用于 T 允许类维护每个列表、队列和堆栈的位置/序数索引。

public class List<T>:
    System.Collections.Generic.List<T>
{
    private object SyncRoot = new object();

    public void Enqueue (T item)
    {
        lock (this.SyncRoot)
        {
            this.Add(item);
        }
    }

    public T Dequeue ()
    {
        T item = default(T);

        lock (this.SyncRoot)
        {
            if (this.Count > 0)
            {
                item = this [0];
                this.RemoveAt(0);
            }
        }

        return (item);
    }

    public void Push (T item)
    {
        lock (this.SyncRoot)
        {
            this.Add(item);
        }
    }

    public T Pop ()
    {
        T item = default(T);

        lock (this.SyncRoot)
        {
            if (this.Count > 0)
            {
                item = this [this.Count - 1];
                this.RemoveAt(this.Count - 1);
            }
        }

        return (item);
    }

    public T PeekQueue ()
    {
        T item = default(T);

        lock (this.SyncRoot)
        {
            if (this.Count > 0)
            {
                item = this [0];
            }
        }

        return (item);
    }

    public T PeekStack ()
    {
        T item = default(T);

        lock (this.SyncRoot)
        {
            if (this.Count > 0)
            {
                item = this [this.Count - 1];
            }
        }

        return (item);
    }
}
  • 由于这是一个粗略的即时实现,我不确定要注意哪些极端情况,因此我会欣赏指向任何现有此类实现的指针或链接。
  • 其次,我对非常大的列表的性能持怀疑态度。从 List 继承的决定是否比对大型列表使用说 LinkedList 更好。就我而言,添加/删除项目比枚举列表具有更高的优先级。
4

2 回答 2

2

以下是如何使用扩展方法完成类似行为... http://weblogs.asp.net/bsimser/archive/2011/01/13/generic-pop-and-push-for-list-lt-t-gt .aspx

通用流行和推送列表

这是我用来扩展通用 List 类以具有与 Stack 类相似的功能的小片段。

Stack 类很棒,但它存在于 System.Object 下的自己的世界中。有一个可以做同样事情的列表不是很好吗?这是代码:

public static class ExtensionMethods    
{ 
    public static T Pop<T>(this List<T> theList)    
    {              
        var local = theList[theList.Count - 1];    
        theList.RemoveAt(theList.Count - 1);    
        return local;   
     }

     public static void Push<T>(this List<T> theList, T item)   
     {   
        theList.Add(item);   
     }   
}

这是一个简单的扩展,但我发现它很有用,希望你也会!享受。

也是扩展方法的链接 http://msdn.microsoft.com/en-us/library/bb383977.aspx

于 2012-09-20T07:45:45.353 回答
0

我猜你必须使用数组作为内部数据存储,它是如何在.NET List 和其他泛型中实现的。例如,由于对内部数组中所有元素的无用处理,而不是开始索引移动,代码的出队效率低下。可以在 ILSpy 中的 C# 反编译中看到:

// System.Collections.Generic.List<T>
/// <summary>Removes the element at the specified index of the <see cref="T:System.Collections.Generic.List`1" />.</summary>
/// <param name="index">The zero-based index of the element to remove.</param>
/// <exception cref="T:System.ArgumentOutOfRangeException">
///   <paramref name="index" /> is less than 0.-or-<paramref name="index" /> is equal to or greater than <see cref="P:System.Collections.Generic.List`1.Count" />.</exception>
public void RemoveAt(int index)
{
    if (index >= this._size)
    {
        ThrowHelper.ThrowArgumentOutOfRangeException();
    }
    this._size--;
    if (index < this._size)
    {
        Array.Copy(this._items, index + 1, this._items, index, this._size - index);
    }
    this._items[this._size] = default(T);
    this._version++;
}

其他功能也可以稍微改进一下。

此外,我注意到 .NET Stack 泛型实现比 List 泛型实现运行缓慢。我认为这是因为在提取时将默认值分配给堆栈的最后一个元素,这与 List 不同:

// System.Collections.Generic.Stack<T>
/// <summary>Removes and returns the object at the top of the <see cref="T:System.Collections.Generic.Stack`1" />.</summary>
/// <returns>The object removed from the top of the <see cref="T:System.Collections.Generic.Stack`1" />.</returns>
/// <exception cref="T:System.InvalidOperationException">The <see cref="T:System.Collections.Generic.Stack`1" /> is empty.</exception>
public T Pop()
{
    if (this._size == 0)
    {
        ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EmptyStack);
    }
    this._version++;
    T result = this._array[--this._size];
    this._array[this._size] = default(T);
    return result;
}
于 2012-09-20T07:07:27.647 回答