如何从SortedDictionary获取最接近我的键的项目?

时间:2012-07-27 15:51:03

标签: c# .net performance collections

目前我在SortedList<T,U>上使用二进制搜索来获取特定数字,如果它不存在,我会获得最接近的下限键项。

我在inserting unsorted data看到它很慢,我做了很多。

有没有办法与SortedDictionary做类似的事情,或者我应该坚持使用SortedList

1 个答案:

答案 0 :(得分:10)

插入数据时,

SortedList<K, V>非常慢,因为每次添加新元素时,它会在内部数组中移动<=N个元素。添加的复杂性为O(N)。然而,它支持二进制搜索,允许在O(log N)中找到确切的元素或其邻居。

平衡二叉树是解决问题的最佳数据结构。 您将能够以对数复杂度执行以下操作:

  1. O(log N)
  2. O(N)SortedList<K, V>中添加项目
  3. 删除O(log N)
  4. 中的项目
  5. 搜索项目或其最近的O(log N)
  6. 在二叉树中查找元素或其最近的下界很简单:

    1. 从树根到孩子垂直穿过树,以便找到你的钥匙。如果密钥&lt;节点,然后转到左边的孩子,否则转到右边的孩子。
    2. 如果找到钥匙,请返回
    3. 如果找不到钥匙,最近的左父母将是您要找的那个(最近的下限)
    4. 如果没有左父母,只需占用最后一个访问过的节点,它就是树中的最小节点。
    5. 有很多文章描述了如何实现二叉树。不过,我将使用一种黑客重用.NET Framework集合:)

      现在,我要向你展示SortedSet<T>,它本身就是红黑树。它有一个缺点,它无法快速找到最近的节点。但是我们知道树中搜索的算法(在1.中描述)并且它是用SortedSet<T>.Contains方法实现的(在底部反编译*)。现在,我们可以使用自定义比较器在遍历期间捕获从根到最后访问节点的所有节点。之后我们可以使用上面的算法找到最近的下界节点:

      public class LowerBoundSortedSet<T> : SortedSet<T> {
      
          private ComparerDecorator<T> _comparerDecorator;
      
          private class ComparerDecorator<T> : IComparer<T> {
      
              private IComparer<T> _comparer;
      
              public T LowerBound { get; private set; }
      
              private bool _reset = true;
      
              public void Reset()
              {
                  _reset = true;
              }
      
              public ComparerDecorator(IComparer<T> comparer)
              {
                  _comparer = comparer;
              }
      
              public int Compare(T x, T y)
              {
                  int num = _comparer.Compare(x, y);
                  if (_reset)
                  {
                      LowerBound = y;
                  }
                  if (num >= 0)
                  {
                      LowerBound = y;
                      _reset = false;
                  }
                  return num;
              }
          }
      
          public LowerBoundSortedSet()
              : this(Comparer<T>.Default) {}
      
          public LowerBoundSortedSet(IComparer<T> comparer)
              : base(new ComparerDecorator<T>(comparer)) {
              _comparerDecorator = (ComparerDecorator<T>)this.Comparer;
          }
      
          public T FindLowerBound(T key)
          {
              _comparerDecorator.Reset();
              this.Contains<T>(key);
              return _comparerDecorator.LowerBound;
          }
      }
      

      您会发现找到最近的节点只需要通常的搜索,即O(log N)。因此,这是解决您问题的最快方案。此集合与查找最近的SortedList<K, V>一样快,并且与SortedSet<T>一样快。

      SortedDictionary<K, V>怎么样?除了一件事之外,它与SortedSet<T>几乎相同:每个键都有一个值。我希望你能用SortedDictionary<K, V>做同样的事情。

      *已解密的SortedSet<T>.Contains方法:

      public virtual bool Contains(T item)
      {
        return this.FindNode(item) != null;
      }
      
      internal virtual SortedSet<T>.Node FindNode(T item)
      {
        for (SortedSet<T>.Node node = this.root; node != null; {
          int num;
          node = num < 0 ? node.Left : node.Right;
        }
        )
        {
          num = this.comparer.Compare(item, node.Item);
          if (num == 0)
            return node;
        }
        return (SortedSet<T>.Node) null;
      }