目前我正在SortedList<T,U>
对特定数字使用二进制搜索,如果它不存在,我会得到最接近的下限键项。
我看到插入未排序的数据相当慢,我经常这样做。
有没有办法用 做类似的事情SortedDictionary
,或者我应该坚持我的SortedList
?
目前我正在SortedList<T,U>
对特定数字使用二进制搜索,如果它不存在,我会得到最接近的下限键项。
我看到插入未排序的数据相当慢,我经常这样做。
有没有办法用 做类似的事情SortedDictionary
,或者我应该坚持我的SortedList
?
SortedList<K, V>
插入数据时非常慢,因为<=N
每次添加新元素时它都会移动内部数组中的元素。加法的复杂度是O(N)
。尽管如此,它支持二进制搜索,允许在O(log N)
.
平衡二叉树是解决问题的最佳数据结构。您将能够执行以下具有对数复杂度的操作:
O(log N)
与O(N)
在SortedList<K, V>
O(log N)
O(log N)
在二叉树中寻找元素或其最近的下界很简单:
有很多文章描述了如何实现二叉树。不过,我将使用一种 hack 重用 .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;
}