【问题标题】:Is there a Lower Bound function on a SortedList<K ,V>?SortedList<K ,V> 上是否有下界函数?
【发布时间】:2010-10-10 07:40:50
【问题描述】:

SortedList&lt;K ,V&gt; 上是否有下界函数?该函数应返回等于或大于指定键的第一个元素。有没有其他类支持这个?

各位 - 请再读一遍这个问题。 我不需要返回密钥(如果存在)的函数。我对没有精确键匹配的场景感兴趣。

我对 O(log n) 时间感兴趣。这意味着我对 foreach 循环没有问题,而是希望有一种有效的方法来做到这一点。

我已经对此做了一些测试。

编译器和运行时机器都没有优化 Linq 语句,因此它们遍历所有集合元素并且速度慢 O(n)。根据 Mehrdad Afshari 的回答,这里是一个在 Keys 集合上以 O(log n) 工作的二进制搜索:

public static int FindFirstIndexGreaterThanOrEqualTo<T>(
            this IList<T> sortedCollection, T key
        ) where T : IComparable<T> {
    int begin = 0;
    int end = sortedCollection.Count;
    while (end > begin) {
        int index = (begin + end) / 2;
        T el = sortedCollection[index];
        if (el.CompareTo(key) >= 0)
            end = index;
        else
            begin = index + 1;
    }
    return end;
}

【问题讨论】:

    标签: c# .net sortedlist


    【解决方案1】:

    SortedList.Keys 集合进行二进制搜索。

    我们开始吧。这是 O(log n):

    private static int BinarySearch<T>(IList<T> list, T value)
    {
        if (list == null)
            throw new ArgumentNullException("list");
        var comp = Comparer<T>.Default;
        int lo = 0, hi = list.Count - 1;
        while (lo < hi) {
                int m = (hi + lo) / 2;  // this might overflow; be careful.
                if (comp.Compare(list[m], value) < 0) lo = m + 1;
                else hi = m - 1;
        }
        if (comp.Compare(list[lo], value) < 0) lo++;
        return lo;
    }
    
    public static int FindFirstIndexGreaterThanOrEqualTo<T,U>
                              (this SortedList<T,U> sortedList, T key)
    {
        return BinarySearch(sortedList.Keys, key);
    }
    

    【讨论】:

    • 不是每次读取Keys属性都会生成集合吗?
    • agsamek:不,它没有重新生成。它将返回一个内部类 KeyList 的实例,它提供对原始集合中元素的直接访问。在此过程中不会复制任何内容。
    • “键和值不复制”是与 SortedDictionary 的主要区别
    • 避免溢出:var m = low + (hi - low)/2
    • @AgentFire O(log(n, base1)) == O(log(n, base2)) 对于所有有效的碱基。证明: log(n, base1) = log(n, base2) * log(base1, base2) 和 log(base1, base2) 是一个常数,这使得它渐近无关。所以你可以在谈论某事的 O(log(..)) 时省略基础
    【解决方案2】:

    不知道,但这是一个简单的 LINQ 语句:

    first = sortedList.Where(x => x >= theObjectForComparison).FirstOrDefault();
    

    first 要么是第一个通过比较的对象,要么是default(T)(通常是null)。

    编辑

    DaveW 的版本:

    first = sortedList.FirstOrDefault(x => x >= theObjectForComparison);
    

    做同样的工作,但可能会更快,但你必须对其进行测试。

    【讨论】:

      【解决方案3】:

      我会使用 LINQ(假设您使用的是 C#3),但使用带有谓词的 FirstOrDefault 的重载:

      first = sortedList.FirstOrDefault(x => x >= theObjectForComparison);
      

      (很多其他的 Enumerable 方法也可以使用谓词,这是一个不错的捷径)

      【讨论】:

        【解决方案4】:

        或者您可以编写自己的扩展方法来执行此操作。请注意,不保证所有这些函数都按顺序执行。

        【讨论】:

          【解决方案5】:

          希望这应该更快,具体取决于 SortedList 的实现。

          public static int FindFirstIndexGreaterThanOrEqualTo<K, V>(
                  this SortedList<K, V> sortedCollection, K key
              ) where V : new()
          {
              if (sortedCollection.ContainsKey(key))
              {
                  return sortedCollection.IndexOfKey(key);
              }
              sortedCollection[key] = new V();
              int retval = sortedCollection.IndexOfKey(key);
              sortedCollection.Remove(key);
              return retval;
          }
          

          【讨论】:

            【解决方案6】:

            SortedList 上是否有下界函数?功能 应该返回等于或大于指定的第一个元素 键。

            这个例子是作为 SortedList 的扩展实现的,它返回大于或等于提供的键的最小元素的值。如果所有键都小于提供的键或提供了空列表,则返回默认值(TValue)

            public static TValue LowerBound<TKey, TValue>(this SortedList<TKey, TValue> list, TKey key) {
              if (list.Count == 0)
                return default;
            
              var comparer = list.Comparer;
              if (comparer.Compare(list.Keys[list.Keys.Count - 1], key) < 0)
                return default; // if all elements are smaller, then no lower bound
            
              int first = 0, last = list.Count - 1;
              while (first < last) {
                var middle = first + (last - first) / 2;
                if (comparer.Compare(list.Keys[middle], key) >= 0)
                  last = middle;
                else
                  first = middle + 1;
              }
              return list[list.Keys[last]];
            }
            

            使用示例:

            SortedList<string, Object> myList = new SortedList<string, Object>();
            ...
            var value = myList.LowerBound<string, Object>("theKey");
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-08-31
              • 2019-07-30
              • 2010-09-21
              • 1970-01-01
              • 2011-07-31
              • 2020-04-08
              • 2016-03-10
              • 2010-09-28
              相关资源
              最近更新 更多