有没有更好的方法为队列实现Remove方法?

时间:2009-10-20 12:49:17

标签: c# .net queue

首先,只是授予我实际上想要Queue<T> - FIFO的功能,通常只需要Enqueue / Dequeue等等 - 所以我我更喜欢“你真正想要的是List<T>”之外的答案(我知道RemoveAt)。

例如,假设我有Queue<DataPoint> dataToProcess个数据点需要按照它们到达的顺序进行处理。然后定期有一些像这样的代码是有道理的:

while (dataToProcess.Count > 0) {
    DataPoint pointToProcess = dataToProcess.Dequeue();
    ProcessDataPoint(pointToProcess);
}

然后假设,无论出于何种原因,我们发现已添加到队列中的特定数据点应该进行处理。如果有类似的方法,那将是理想的:

dataToProcess.Remove(badPoint);

我理解,实际上没有可行的方法来使Remove方法不涉及某种形式的枚举;但是,因为Queue<T>并没有真正让你随便走进并随机删除一些项目,我能想出的唯一解决方案是:

bool Remove(T item) {
    bool itemFound = false;

    // set up a temporary queue to take items out
    // one by one
    Queue<T> receivingQueue = new Queue<T>();

    // move all non-matching items out into the
    // temporary queue
    while (this.Count > 0) {
        T next = this.Dequeue();
        if (next.Equals(item)) {
            itemFound = true;
        } else {
            receivingQueue.Enqueue(next);
        }
    }

    // return the items back into the original
    // queue
    while (receivingQueue.Count > 0) {
        this.Enqueue(receivingQueue.Dequeue());
    }

    return itemFound;
}
这是荒谬的吗?肯定看起来不好,但除了编写自定义类之外,我无法真正看到更好的方法。即便如此,我认为实施Remove方法的最佳方式是在内部使用LinkedList<T>

5 个答案:

答案 0 :(得分:25)

我认为切换到一个内部具有LinkedList的新自定义类只需要几分钟时间,并且比现在的性能更高。

public class SpecialQueue<T>
{
    LinkedList<T> list = new LinkedList<T>();

    public void Enqueue(T t)
    {
        list.AddLast(t);
    }

    public T Dequeue()
    {
        var result = list.First.Value;
        list.RemoveFirst();
        return result;
    }

    public T Peek()
    {
        return list.First.Value;
    }

    public bool Remove(T t)
    {
        return list.Remove(t);
    }

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

答案 1 :(得分:9)

另一种方法是将项目留在队列中,并在读取时忽略它们。类似的东西:

T DequeueFiltered(HashSet<T> ignored) {
   T item;
   while (ignored.Contains(item = Dequeue())) {
      ignored.Remove(item);
   }
   return item;
}

答案 2 :(得分:1)

我是初学者但是我最近设法解决了相同(或非常相似)的问题。 我希望它有所帮助。

这是我们的队列:

Queue<T> dataToProcess = new Queue<T>();

如果我们将所有入队项的副本放入一个哈希集(例如:

),该怎么办?
HashSet<T> pointsToProcess = new HashSet<T>(); 

所以当排队元素时,我们也会向hashset添加相同的数据。

当事实证明我们不需要元素时,我们会从该hashset中删除它

pointsToProcess.Remove(element);

所以当我们必须“使用”队列的下一个元素时,

我们检查是否真的需要处理它(如果它是hashset的成员),否则它必须被忽略,我们可以摆脱它,

while (dataToProcess.Count > 0) {


if  pointsToProcess.Contains(dataToProcess.Peek())
{


// processing data


}

else
{

// error message and

dataToProcess.Dequeue();

}


}

答案 3 :(得分:1)

请参阅c# Adding a Remove(int index) method to the .NET Queue class

队列是最有效的排队结构,在列表数据结构上实现队列效率不高。

  

虽然没有内置方式,但您不应使用List   结构或其他结构,IFF删除不是经常的操作。

     

如果您通常是入队和出队,但只是偶尔   删除,然后你应该能够负担得起队列重建时   除去。

查看两个简单扩展方法的链接

public static void Remove<T>(this Queue<T> queue, T itemToRemove) where T : class

public static void RemoveAt<T>(this Queue<T> queue, int itemIndex) where T : class

答案 4 :(得分:-2)

var first = Q.Dequeue();
if (first.Id.Equals(deleteId)) return;
Q.Enqueue(first);

while (Q.Peek() != first)
{
   var r = Q.Dequeue();
   if(!r.Id.Equals(deleteId)) Q.Enqueue(r);
}