我需要为线性插值编写一些代码,我试图找出一种最有效的方法来搜索SortedList<K, V>
的键,以查找围绕我的目标键的上下键。
SortedList<int, double> xyTable = new SortedList<int, double>()
{
{1, 10}, {2, 20}, {3, 30}, {4,40}
};
double targetX = 3.5;
搜索列表并确定3.5介于3和4之间的最有效方法是什么?我有一个适用于整数的方法/作弊(暂时将目标密钥插入列表然后找到索引)但我想我会问专业人员所以我可以生成高质量的代码。
感谢。
答案 0 :(得分:6)
二进制搜索在列表中为您提供了不错的性能。但是SortedList
上的Keys属性属于IList
类型,而BinarySearch
上的List
属性已定义IList
。幸运的是,您可以在此相关问题中找到{{1}}的二进制搜索实现:
答案 1 :(得分:5)
在我的情况下,源SortedList
没有太大变化,因为它被用作查找表。因此,在这种情况下,将SortedList
转换为List<T>
一次是有意义的。之后,使用List<T>
...
double targetX = 3.5;
// Assume keys are doubles, may need to convert to doubles if required here.
// The below line should only be performed sparingly as it is an O(n) operation.
// In my case I only do this once, as the list is unchanging.
List<double> keys = xyTable.Keys.ToList();
int ipos = keys.BinarySearch(targetX);
if (ipos >= 0)
{
// exact target found at position "ipos"
}
else
{
// Exact key not found: BinarySearch returns negative when the
// exact target is not found, which is the bitwise complement
// of the next index in the list larger than the target.
ipos = ~ipos;
if (ipos >= 0 && ipos < keys.Count)
{
if (ipos > 0)
{
// target is between positions "ipos-1" and "ipos"
}
else
{
// target is below position "ipos"
}
}
else
{
// target is above position "ipos"
}
}
答案 2 :(得分:2)
来自MSDN,
SortedList对象的元素按键按照创建SortedList时指定的特定IComparer实现进行排序,或者根据键本身提供的IComparable实现进行排序。 索引序列基于排序顺序。添加元素时,会以正确的排序顺序将其插入到SortedList中,并且索引会相应地进行调整。删除元素后,索引也会相应调整。因此,在SortedList中添加或删除元素时,特定键/值对的索引可能会更改。
*****此方法使用二进制搜索算法;因此,此方法是O(log n)操作,其中n是Count。*****
从.NET Framework 2.0开始,此方法使用集合的对象的项目上的Equals和CompareTo方法来确定项是否存在。在早期版本的.NET Framework中,通过对集合中对象的item参数使用Equals和CompareTo方法来进行此确定。
换句话说,SortedList中的IndexOfKey方法实际上已经使用了binarySearch算法,所以在你的情况下不需要将SortedList转换为List。
希望有所帮助......
答案 3 :(得分:1)
public class Bounds
{
int lower;
int upper;
public Bounds(int lower, int upper)
{
this.lower = lower;
this.upper = upper;
}
}
public Bounds BinarySearch(List<int> keys, double target)
{
// lower boundary case returns the smallest key as the lower and upper bounds
if (target < keys[0])
return new Bounds(0, 0);
else if (target < keys[1])
return new Bounds(0, 1);
// upper boundary case returns the largest key as the lower and upper bounds
else if (target > keys[keys.Length - 1])
return new Bounds(keys.Length - 1, keys.Length - 1);
else if (target > keys[keys.Length - 2])
return new Bounds(keys.Length - 2, keys.Length - 1);
else
return BinarySearch(keys, target, 0, keys.Length - 1);
}
// 'keys' is a List storing all of the keys from your SortedList.
public Bounds BinarySearch(List<int> keys, double target, int lower, int upper)
{
int middle = (upper + lower)/2;
// target is equal to one of the keys
if (keys[middle] == target)
return new Bounds(middle - 1, middle + 1);
else if (keys[middle] < target && keys[middle + 1] > target)
return new Bounds(middle, middle + 1);
else if (keys[middle] > target && keys[middle - 1] < target)
return new Bounds(middle - 1, middle);
if (list[middle] < target)
return BinarySearch(list, target, lower, upper/2 - 1);
if (list[middle] > target)
return BinarySearch(list, target, upper/2 + 1, upper);
}
这可能有用..我没有测试出来。如果没有,希望它足够接近你可以使用它进行微调。这是一个奇怪的问题,因此我处理了所有边界情况,因此当范围降至2个元素或更少时,我不必考虑算法会做什么。