我如何实现QueueDictionary,即C#中队列和字典的组合?

我如何实现QueueDictionary,即C#中队列和字典的组合?,c#,data-structures,C#,Data Structures,基本上,我想要的数据结构将镜像MSMQ,但会在内存中,因为它正在一个进程中使用。通过镜像MSMQ,我的意思是您将对象排队,然后您可以将对象排队或使用密钥检索它们。这是我的初步尝试。我这次尝试的主要问题是Get by id会被频繁使用,因此队列中会有很多“死”对象 public class QueueDictionary<TKey, TValue> { private readonly Queue _queue = new Queue(); private readon

基本上,我想要的数据结构将镜像MSMQ,但会在内存中,因为它正在一个进程中使用。通过镜像MSMQ,我的意思是您将对象排队,然后您可以将对象排队或使用密钥检索它们。这是我的初步尝试。我这次尝试的主要问题是Get by id会被频繁使用,因此队列中会有很多“死”对象

public class QueueDictionary<TKey, TValue>
{
    private readonly Queue _queue = new Queue();
    private readonly Dictionary<TKey, TValue> _dictionary = new Dictionary<TKey, TValue>();
    private readonly object _syncRoot = new object();

    public TValue Dequeue()
    {
        lock (_syncRoot)
        {
            TKey key = (TKey)_queue.Dequeue();
            while (!_dictionary.ContainsKey(key))
                key = (TKey)_queue.Dequeue();
            return _dictionary[key];
        }
    }

    public TValue Get(TKey key)
    {
        lock (_syncRoot)
        {
            TValue result = _dictionary[key];
            _dictionary.Remove(key);
            return result;
        }
    }

    public void Enqueue(TKey key, TValue value)
    {
        lock (_syncRoot)
        {
            _dictionary.Add(key, value);
            _queue.Enqueue(key);
        }
    }
}
公共类排队字典
{
私有只读队列_Queue=new Queue();
专用只读词典_Dictionary=新词典();
私有只读对象_syncRoot=新对象();
公共TValue出列()
{
锁定(\u syncRoot)
{
TKey=(TKey)u queue.Dequeue();
while(!\u dictionary.ContainsKey(key))
key=(TKey)u queue.Dequeue();
返回字典[键];
}
}
公共TValue Get(TKey)
{
锁定(\u syncRoot)
{
t值结果=_字典[键];
_删除(键);
返回结果;
}
}
public void排队(TKey key,TValue value)
{
锁定(\u syncRoot)
{
_添加(键、值);
_queue.Enqueue(key);
}
}
}

您可以使用LinkedList,而不是在内部使用队列。然后,您可以在字典中存储密钥和LinkedListNode。然后,当您从字典中删除该项时,可以从链接列表中取消LinkedListNode的链接。当然,您失去了队列的局部性,但获得了随机访问的性能

这是一个快速而肮脏的例子,没有经过测试,所以请原谅任何错误,不要检查错误。例如,您应该检查队列是否为空,确保字典中不存在具有相同密钥的项等

public class QueueDictionary<TKey, TValue>
{
  private readonly LinkedList<Tuple<TKey, TValue>> _queue =
    new LinkedList<Tuple<TKey, TValue>>();

  private readonly Dictionary<TKey, LinkedListNode<Tuple<TKey, TValue>>> 
    _dictionary = new Dictionary<TKey, LinkedListNode<Tuple<TKey, TValue>>>();

  private readonly object _syncRoot = new object();

  public TValue Dequeue()
  {
    lock (_syncRoot)
    {
      Tuple<TKey, TValue> item = _queue.First();
      _queue.RemoveFirst();
      _dictionary.Remove(item.Item1);
      return item.Item2;
    }
  }

  public TValue Dequeue(TKey key)
  {
    lock (_syncRoot)
    {
      LinkedListNode<Tuple<TKey, TValue>> node = _dictionary[key];
      _dictionary.Remove(key);
      _queue.Remove(node);
      return node.Value.Item2;
    }
  }

  public void Enqueue(TKey key, TValue value)
  {
    lock (_syncRoot)
    {
      LinkedListNode<Tuple<TKey, TValue>> node = 
        _queue.AddLast(new Tuple<TKey, TValue>(key, value));
      _dictionary.Add(key, node);
    }
  }
}
公共类排队字典
{
专用只读链接列表队列=
新建LinkedList();
专用只读词典
_字典=新字典();
私有只读对象_syncRoot=新对象();
公共TValue出列()
{
锁定(\u syncRoot)
{
元组项=_queue.First();
_queue.RemoveFirst();
_删除字典(项目1);
返回项目1.2;
}
}
公共TValue出列(TKey)
{
锁定(\u syncRoot)
{
LinkedListNode节点=_字典[键];
_删除(键);
_队列移除(节点);
返回node.Value.Item2;
}
}
public void排队(TKey key,TValue value)
{
锁定(\u syncRoot)
{
LinkedListNode节点=
_AddLast(新元组(键,值));
_添加(键,节点);
}
}
}

如果您使用一个双链接列表作为队列,这样您就可以完全控制入队、出队,特别是Get方法,该怎么办。因此,在Get方法中,您可以简单地从双链接列表中删除键。

您的对象可以像队列一样工作,而无需实际使用队列类作为其内部存储。根据您计划保留的项目数量,只维护一个LinkedList(T)可能比同时将项目存储在LinkedList(T)和字典(K,V)中更容易


但基本上,您可以使用LinkedList(T),而不是在内部使用队列,只需将新项目添加到列表的末尾,然后从列表的前面退出队列。当您需要按键查找一个时,您只需扫描列表以查找匹配的键,或者如果项目的数量使其性能不佳,您可以使用字典(K,LinkedListNode(T))将存储空间加倍,并使用字典查找键。

“队列中会有大量“死”对象。”-那就不需要排队了……为什么会有“死”的东西?您似乎没有删除
Get
中的任何内容。。。如果你没有作弊,你似乎不需要
while
循环。。。哪一个btw可能应该保护自己不受空队列的影响。@Marc-我认为Get方法是OP请求帮助的方法,因为您不能从队列中删除任意项。
Get
从队列中删除对象的意图也是这样吗?或者这仅仅是一个“窥视”界面?好问题-我假设他希望能够从队列中按键删除一个项目。我认为这会很好地工作。我还希望在Dequeue(TKey)方法中使用“_dictionary.Remove(key);”。