C#中的CircularBuffer IDictionary?

时间:2009-08-06 15:55:38

标签: c# dictionary buffer circular-buffer

我需要一个CircularBuffer IDictionary。任何人都可以向我指出一个良好的开源实现。

这是一个具有最大容量的IDictionary,比如配置为100个项目,当添加项目101时,将从字典中弹出/删除原始的第一个项目,从而确保项目计数永远不会超过100个。

由于

6 个答案:

答案 0 :(得分:12)

要保持O(1)插入(删除最旧的项目超过100)和O(1)查找,您需要一个实现IDictionary 的类保留内部有序列表。如果内存更受关注,那么像SortedList这样的BST实现可能更合适。无论如何,您的课程将同时包含T[]Dictionary<T,K>(或SortedList<T,K>)。执行您自己的循环缓冲区索引(简单),并在添加,删除等方法中保持两个集合的最新状态。你会:

  • O(1)入队(回来)
  • O(n)插入违反添加顺序(因为您必须保持阵列最新);你可能永远不会需要这个
  • O(1)出队(从前面)
  • O(1)或O(log n)键控查找

将其设为通用并实施IDictionary<T,K>IDictionary,因为没有理由不这样做,您将获得性能优势。

一个主要考虑因素:您如何处理重复密钥?我假设你实际上不能保留重复项,所以:

  • 抛出异常(如果没有重复的密钥,那么插入两次只是一个错误)
  • 向后移动:检查词典的Count,然后使用this[key]索引器插入密钥。如果大小增加,则检查列表是否已具有最大容量,从列表和字典中删除前项并将新项添加到后面。如果字典的大小没有增加,请将项目从列表中的现有位置移动到列表的后面。
  • 不移动覆盖:与上一项相同,但您不必弄乱列表。

最后,请注意内部列表保留键,而不是值。这是为了确保在超出列表容量时O(1)出列。

答案 1 :(得分:4)

在谷歌搜索五分钟后发现两个:

答案 2 :(得分:3)

我不知道任何这样的实现,但它自己听起来并不难。由于字典没有任何固有顺序,因此字典中的键或值类型需要具有一些属性,表示它插入字典的顺序。然后,在覆盖Add方法时,它可以检查计数是否为最大值。如果是,则查看现有的键值对以查找其insert-order属性最低的那个,并将其替换为新的键值对。否则,照常插入新的键值对。

答案 3 :(得分:2)

我不久前在C#3.0中编写了一个循环缓冲区的完整实现,并在CodePlex上发布了源代码。它遵循BCL设计指南,并实现System.Collections的所有适当接口。

我认为应该很容易适应使用Dictionary<TKey, TValue>作为支持集合而不是List<T>

答案 4 :(得分:0)

这个怎么样:

    public class CircularDictionary<TKey, TValue> : Dictionary<TKey, TValue>
    {
        private Queue<TKey> m_ItemInsertList = new Queue<TKey>();
        private int m_ItemsToHold = 100;

        public int ItemsToHold
        {
            get { return m_ItemsToHold; }
            set {
                if (value < 1)
                    throw new ArgumentException("Items to hold must be at least 1");
                m_ItemsToHold = value; 
            }
        }

        public new void Add(TKey key, TValue value)
        {
            base.Add(key, value);
            if (m_ItemInsertList.Count == m_ItemsToHold)
                base.Remove(m_ItemInsertList.Dequeue());
            m_ItemInsertList.Enqueue(key);
        }
    }

答案 5 :(得分:0)

我通过System.Data.Sqlite(http://sqlite.phxsoftware.com/)包装器使用SQLite数据库表实现了类似的功能。您可以将其存储在磁盘上或作为内存数据库。您可以选择是否具有唯一键,并让数据库引擎为您处理索引。您甚至可以为每个键设置多个值。

当您写入表格时,请检查您是否处于100个记录限制,如果是,则在插入之前删除。如果要保留唯一键,SQLite支持“插入或替换”命令。也许这不像自定义IDictionary派生那么优雅,但它可以工作,它很灵活,而且很容易在线程之间共享。