我将一些C++码C#呼吁std::地图::lower_bound(k)找到一个进入的地图,其关键是等于或大于k.然而,我看不到任何方式做同样的事情。净的SortedDictionary.我怀疑我能实现一种解决方法使用SortedList,但不幸的是SortedList太慢(O(n)插入和删除键)。我能做些什么?

注:我找到一个解决方法使用,利用我的特定场景...具体地说,我的钥匙是一个人口密集的整数开始超过0,所以我用一个列表<TValue> 因为我的字典的名单索引服务作为关键,并且寻找一个关键等于或大于k可以在仅仅几个回路迭代。但是,它仍然会很高兴见到原来的问题的答案。

有帮助吗?

解决方案 4

我创建了三个数据结构有关的B+树木提供这种功能的任何数据类型: BList<T>, BDictionary<K,V>BMultiMap<K,V>.每一个这些数据结构的提供 FindLowerBound()FindUpperBound() 方法工作像C++'s lower_boundupper_bound.

其他提示

花了工作了几个月,但最后我能提供至少部分解决了这个问题......我把它称为紧凑型帕特里夏特里,一个排序的字典,提供了一个“查找下一个较大的键”操作。

http://www.codeproject.com/KB/recipes/cptrie.aspx

这只是一个部分解决方案,因为只有某些类型的密钥被支持,即byte[]string,以及所有的原始整数类型(Int8..UInt64)。此外,字符串排序是大小写敏感的。

的问题是,一个字典/哈希表被设计为以基于输入值的唯一存储器位置到达,所以需要被设计,以容纳相关的每次存储值的范围内的数据结构,和在同一时间正确地更新每个间隔

我觉得跳表(或平衡二叉树)可以帮助你。虽然无法在O(N)中执行查找,就可以做的对数,并且仍然快于树木。

我知道这是不是一个正确的答案,因为我不能说了.NET基础类库已经包含了这样的类,你会很遗憾不得不实现一个自己,或者找出支持它给你一个第三方组件。似乎是一个很好的例子,在上 CodeProject上这里,虽然。

您可以尝试下面我写的代码。使用它的二进制搜索,因此假设该列表/阵列是预先排序。

public static class ListExtensions
{
    public static int GetAtMostIndex<TItem, TValue>(/*this*/ IList<TItem> list, TValue value, Func<TItem, TValue, int> comparer)
    {
        return GetAtMostIndex(list, value, comparer, 0, list.Count);
    }

    public static int GetAtLeastIndex<TItem, TValue>(/*this*/ IList<TItem> list, TValue value, Func<TItem, TValue, int> comparer)
    {
        return GetAtLeastIndex(list, value, comparer, 0, list.Count);
    }

    public static int GetAtMostIndex<TItem, TValue>(/*this*/ IList<TItem> list, TValue value, Func<TItem, TValue, int> comparer, int index, int count)
    {
        if (count == 0)
        {
            return -1;
        }

        int startIndex = index;
        int endIndex = index + count - 1;
        int middleIndex = 0;
        int compareResult = -1;

        while (startIndex < endIndex)
        {
            middleIndex = (startIndex + endIndex) >> 1; //  / 2
            compareResult = comparer.Invoke(list[middleIndex], value);

            if (compareResult > 0)
            {
                endIndex = middleIndex - 1;
            }
            else if (compareResult < 0)
            {
                startIndex = middleIndex + 1;
            }
            else
            {
                return middleIndex;
            }
        }

        if (startIndex == endIndex)
        {
            compareResult = comparer.Invoke(list[startIndex], value);

            if (compareResult <= 0)
            {
                return startIndex;
            }
            else
            {
                int returnIndex = startIndex - 1;

                if (returnIndex < index)
                {
                    return -1;
                }
                else
                {
                    return returnIndex;
                }
            }
        }
        else
        {
            //todo: test
            return startIndex - 1;
        }
    }

    public static int GetAtLeastIndex<TItem, TValue>(/*this*/ IList<TItem> list, TValue value, Func<TItem, TValue, int> comparer, int index, int count)
    {
        if (count == 0)
        {
            return -1;
        }

        int startIndex = index;
        int endIndex = index + count - 1;
        int middleIndex = 0;
        int compareResult = -1;

        while (startIndex < endIndex)
        {
            middleIndex = (startIndex + endIndex) >> 1; //  / 2
            compareResult = comparer.Invoke(list[middleIndex], value);

            if (compareResult > 0)
            {
                endIndex = middleIndex - 1;
            }
            else if (compareResult < 0)
            {
                startIndex = middleIndex + 1;
            }
            else
            {
                return middleIndex;
            }
        }

        if (startIndex == endIndex)
        {
            compareResult = comparer.Invoke(list[startIndex], value);

            if (compareResult >= 0)
            {
                return startIndex;
            }
            else
            {
                int returnIndex = startIndex + 1;

                if (returnIndex >= index + count)
                {
                    return -1;
                }
                else
                {
                    return returnIndex;
                }
            }
        }
        else
        {
            return endIndex + 1;
        }
    }
}

找到最接近K:

dict.Keys.Where(i => i >= K).OrderBy(i => i).First();

或快得多:

public int? GetNearestKey(dict, K) 
{
    int? lowerK = null;
    foreach (int key in dict.Keys)
    {
        if (key == K) 
        {
            lowerK = K;
            break; 
        }
        else if (key >= K && (!lowerK.HasValue || key < lowerK))
        {
            lowerK = key;
        }
    }
    return lowerK;
}

有没有在基本框架二叉搜索树集合实现,所以你要么必须建立一个或找到一个实现。如你所指出的,排序列表最接近在搜索方面,而且是慢的(由于其底层数组实现),用于插入/缺失。

我认为有一个错误有关的问题 SortedList 复杂性。

SortedList 已O(日志(n))分摊的复杂性 插入 新的项目。如果你事先知道的能力,这是可以做到在O(日志(n))中最糟糕的情况。

可以用下面的扩展方法SortedSet<T>做到这一点:

public static class SortedSetExtensions
{
    public static bool FindLowerOrEqualThan<T>(this SortedSet<T> set, T value, out T first)
    {
        if(set.Count == 0)
        {
            first = default(T);
            return false;
        }

        var minimum = set.Min;

        if(set.Comparer.Compare(minimum, value) > 0)
        {
            first = default(T);
            return false;
        }

        first = set.GetViewBetween(minimum, value).Max;
        return true;
    }

    public static bool FindGreaterOrEqualThan<T>(this SortedSet<T> set, T value, out T first)
    {
        if (set.Count == 0)
        {
            first = default(T);
            return false;
        }

        var maximum = set.Max;

        if (set.Comparer.Compare(maximum, value) < 0)
        {
            first = default(T);
            return false;
        }

        first = set.GetViewBetween(value, maximum).Min;
        return true;
    }
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top