【问题标题】:Is there a better way to implement a Remove method for a Queue?有没有更好的方法来为队列实现 Remove 方法?
【发布时间】:2010-12-08 08:08:40
【问题描述】:

首先,请承认我确实想要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&lt;T&gt;

【问题讨论】:

  • PowerCollections (@codeplex) 可能对你有用

标签: c# .net queue


【解决方案1】:

我认为切换到内部具有 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; } }
}

【讨论】:

  • 我想我会倾向于同意你的观点,这就是我问这个问题的原因——因为我想不出用Queue&lt;T&gt; 做这件事的好方法,但我我想也许其他人能看到我遗漏的东西。
  • 此外,您可以通过在出队时入队来加速现有方法,而不是将队列保存到临时列表中。
  • @Jake:很聪明——没想到!尽管您的LinkedList 实现确实看起来更好(并且与我会做的相匹配...毕竟,我想这几乎是的方法)。
【解决方案2】:

另一种方法可能是将项目留在队列中,并在您从中读取时忽略它们。比如:

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

【讨论】:

  • 我觉得这是一个非常聪明的建议。我可以看到的一个问题是,由于该项目仍然队列中,因此还必须有GetEnumerator 的过滤形式,以便在枚举期间跳过被忽略的项目。跨度>
【解决方案3】:

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

这是我们的队列:

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

如果我们将所有入队项的副本放入哈希集中会怎样(例如:

HashSet<T> pointsToProcess = new HashSet<T>(); 

因此,在对元素进行排队时,我们还将相同的数据添加到哈希集中。

当我们不需要某个元素时,我们将其从该哈希集中删除

pointsToProcess.Remove(element);

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

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

while (dataToProcess.Count > 0) {


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


// processing data


}

else
{

// error message and

dataToProcess.Dequeue();

}


}

【讨论】:

    【解决方案4】:

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

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

    虽然没有内置方式,但您不应该使用 List 结构或其他结构,IFF Remove 不是一个频繁的操作。

    如果您通常会入队和出队,但只是偶尔 删除,那么您应该能够负担得起队列重建的时间 删除。

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

    public static void Remove&lt;T&gt;(this Queue&lt;T&gt; queue, T itemToRemove) where T : class

    public static void RemoveAt&lt;T&gt;(this Queue&lt;T&gt; queue, int itemIndex) where T : class

    【讨论】:

      【解决方案5】:
      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);
      } 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-08-19
        • 1970-01-01
        • 2011-10-23
        • 2021-11-15
        • 2010-11-05
        • 2012-01-11
        • 2013-08-04
        • 1970-01-01
        相关资源
        最近更新 更多