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