在C#中,是否存在一个队列,该队列在对象的生命周期中只能容纳一次对象?

在C#中,是否存在一个队列,该队列在对象的生命周期中只能容纳一次对象?,c#,data-structures,queue,C#,Data Structures,Queue,我需要一个数据结构,它是一种特殊类型的队列。我想知道的是,如果我的队列的一个实例曾经包含一个对象X,那么在这个实例中就不可能再次将X排队。如果使用X调用,排队方法应该什么也不做,比如尝试向HashSet添加重复值 用法示例: MyQueue<int> queue = new MyQueue<int>(); queue.Enqueue(5); queue.Enqueue(17); queue.Enqueue(28); queue.Enqueue(17); int

我需要一个数据结构,它是一种特殊类型的队列。我想知道的是,如果我的队列的一个实例曾经包含一个对象X,那么在这个实例中就不可能再次将X排队。如果使用X调用,排队方法应该什么也不做,比如尝试向HashSet添加重复值

用法示例:

MyQueue<int> queue = new MyQueue<int>(); 
queue.Enqueue(5); 
queue.Enqueue(17); 
queue.Enqueue(28); 
queue.Enqueue(17); 
int firstNumber = queue.Dequeue(); 
queue.Enqueue(5); 
queue.Enqueue(3); 

List<int> queueContents = queue.ToList(); //this list should contain {17, 28, 3}
MyQueue=newmyqueue();
排队。排队(5);
排队。排队(17);
排队。排队(28);
排队。排队(17);
int firstNumber=queue.Dequeue();
排队。排队(5);
排队。排队(3);
List queueContents=queue.ToList()//此列表应包含{17,28,3}
我在MSDN上四处寻找,但找不到这样的类。它是否存在,还是我必须自己实施


我想我也可以使用不同的数据结构,但访问总是FIFO,所以我认为队列将是最有效的。另外,我还不知道还有哪种结构能提供这种“实例生命周期内的唯一性”特性

你必须自己实施

一个想法是,当您将该元素排入队列时,只需将其添加到
HashSet

然后,当您想要排队时,只需检查项目的
哈希集
,如果它存在,则不要排队


由于您希望在队列的剩余生存期内防止排队,因此您可能永远都不想从
哈希集中删除

,我将执行类似的操作:

class UniqueQueue<T>
{
    private readonly Queue<T> queue = new Queue<T>();
    private HashSet<T> alreadyAdded = new HashSet<T>();

    public virtual void Enqueue(T item)
    {
        if (alreadyAdded.Add(item)) { queue.Enqueue(item); }
    }
    public int Count { get { return queue.Count; } }

    public virtual T Dequeue()
    {
        T item = queue.Dequeue();
        return item;
    }
}
类唯一队列
{
私有只读队列队列=新队列();
私有HashSet alreadyAdded=新HashSet();
公共虚拟空位排队(T项)
{
if(alreadyAdded.Add(item)){queue.Enqueue(item);}
}
公共整数计数{get{return queue.Count;}}
公共虚拟T出列()
{
T item=queue.Dequeue();
退货项目;
}
}

注意,此代码的大部分是从中借用的。

您可以使用基本队列,但修改Enqueue方法以验证以前输入的值。在这里,我使用hashset来包含前面的值:

public class UniqueValueQueue<T> : Queue<T>
{
    private readonly HashSet<T> pastValues = new HashSet<T>();

    public new void Enqueue(T item)
    {
        if (!pastValues.Contains(item))
        {
            pastValues.Add(item);

            base.Enqueue(item);
        }
    }
}
public类UniqueValueQueue:Queue
{
private readonly HashSet passvalues=new HashSet();
公共新作废排队(T项)
{
如果(!pastValues.Contains(项))
{
添加(项目);
基本。排队(项目);
}
}
}
使用您的测试用例

UniqueValueQueue<int> queue = new UniqueValueQueue<int>();
queue.Enqueue(5);
queue.Enqueue(17);
queue.Enqueue(28);
queue.Enqueue(17);
int firstNumber = queue.Dequeue();
queue.Enqueue(5);
queue.Enqueue(3);

List<int> queueContents = queue.ToList();
UniqueValueQueue队列=新的UniqueValueQueue();
排队。排队(5);
排队。排队(17);
排队。排队(28);
排队。排队(17);
int firstNumber=queue.Dequeue();
排队。排队(5);
排队。排队(3);
List queueContents=queue.ToList();

queueContents包含17、28和3。

这只是的一个扩展版本,它只是稍微充实了一些,并且支持更多的接口。(模拟队列的接口)

密封类唯一队列:IEnumerable,ICollection,IEnumerable
{
专用只读队列;
已添加私有只读哈希集;
公共唯一队列(IEqualityComparer比较器)
{
队列=新队列();
alreadyAdded=新哈希集(比较器);
}
公共唯一队列(IEnumerable集合、IEqualityComparer比较器)
{
//这样,如果枚举器在每个枚举中的行为不同,枚举不会发生两次。
var localCopy=collection.ToList();
队列=新队列(本地副本);
alreadyAdded=新哈希集(localCopy,comparer);
}
公共唯一队列(int容量、IEqualityComparer比较器)
{
队列=新队列(容量);
alreadyAdded=新哈希集(比较器);
}
//以下是使用默认比较器的构造函数。通过为比较器传入null,它将只为类型使用默认比较器。
public UniqueQueue():此((IEqualityComparer)null){}
公共唯一队列(IEnumerable集合):此(集合,null){}
公共唯一队列(int capacity):此(capacity,null){}
/// 
///尝试将对象排队,如果该对象过去曾添加到队列中,则返回false。
/// 
///要排队的项目
///如果成功添加对象,则为True;如果未成功添加,则为false
公共布尔排队(T项)
{
如果(!alreadyAdded.Add(项目))
返回false;
排队。排队(项目);
返回true;
}
公共整数计数
{
获取{return queue.Count;}
}
公共T出列()
{
return queue.Dequeue();
}
IEnumerator IEnumerable.GetEnumerator()
{
返回((IEnumerable)队列);
}
IEnumerator IEnumerable.GetEnumerator()
{
返回((IEnumerable)队列);
}
void ICollection.CopyTo(数组,int索引)
{
((ICollection)队列).CopyTo(数组,索引);
}
布尔ICollection.IsSynchronized
{
获取{return((ICollection)队列).IsSynchronized;}
}
对象ICollection.SyncRoot
{
获取{return((ICollection)queue.SyncRoot;}
}
}

我很确定您必须推出自己的。这可能会有所帮助:@Eugene OP已经在问题中提到了HashSet。@Eugene如果我从HashSet中删除一个元素,我可以稍后再添加它。我想要一个不允许我这样做的结构。类似于具有内存和元素顺序的哈希集。请注意,要使其正常工作,无论传递到队列的是何种类型,都必须支持适当的相等比较(
.Equals(object)
.GetHashCode()
),您应该在此处使用
哈希集而不是
列表。在阅读了其他答案后,我同意列表的表现会更糟。不幸的是,我以前从未使用过哈希集,所以我不知道它。事实上,我希望我能对其他一些答案投赞成票。当然,我只是想在我公开同意HashSet的优点之前确保我了解它们的优点。而不是
if(alreadyAdd)
sealed class UniqueQueue<T> : IEnumerable<T>, ICollection, IEnumerable
{
    private readonly Queue<T> queue;
    private readonly HashSet<T> alreadyAdded;

    public UniqueQueue(IEqualityComparer<T> comparer)
    {
        queue = new Queue<T>();
        alreadyAdded = new HashSet<T>(comparer);
    }

    public UniqueQueue(IEnumerable<T> collection, IEqualityComparer<T> comparer)
    {
        //Do this so the enumeration does not happen twice in case the enumerator behaves differently each enumeration.
        var localCopy = collection.ToList();

        queue = new Queue<T>(localCopy);
        alreadyAdded = new HashSet<T>(localCopy, comparer);
    }

    public UniqueQueue(int capacity, IEqualityComparer<T> comparer)
    {
        queue = new Queue<T>(capacity);
        alreadyAdded = new HashSet<T>(comparer);
    }

    //Here are the constructors that use the default comparer. By passing null in for the comparer it will just use the default one for the type.
    public UniqueQueue() : this((IEqualityComparer<T>) null) { }
    public UniqueQueue(IEnumerable<T> collection) : this(collection, null) { }
    public UniqueQueue(int capacity) : this(capacity, null) { }

    /// <summary>
    /// Attempts to enqueue a object, returns false if the object was ever added to the queue in the past.
    /// </summary>
    /// <param name="item">The item to enqueue</param>
    /// <returns>True if the object was successfully added, false if it was not</returns>
    public bool Enqueue(T item)
    {
        if (!alreadyAdded.Add(item))
            return false;

        queue.Enqueue(item);
        return true;
    }

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

    public T Dequeue()
    {
        return queue.Dequeue();
    }

    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
        return ((IEnumerable<T>)queue).GetEnumerator();
    }

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

    void ICollection.CopyTo(Array array, int index)
    {
        ((ICollection)queue).CopyTo(array, index);
    }

    bool ICollection.IsSynchronized
    {
        get { return ((ICollection)queue).IsSynchronized; }
    }

    object ICollection.SyncRoot
    {
        get { return ((ICollection)queue).SyncRoot; }
    }
}