我有一个对象列表。它们都与该对象唯一的范围相关联。没有重叠。我想要一种方法来尽可能快地访问与该范围相关联的对象。目前的数据结构都不适合这种情况。这是一个图表:
Element 1
0.0-1.39
Element 2
1.4-2.09
Element 3
2.1-4.89
Element 4
4.9-5.0
什么是理想的是一种键/字典类型的东西,我可以请求范围值为1.7的元素,它将返回元素2.
后备是一个列表,但这意味着每次迭代它,根据大小,它理论上可能会变慢。
答案 0 :(得分:1)
没有重叠
该假设允许您简单地存储一个地图,其中key是您要查找的下限(或上限),并找到与它最接近的 1 元素。使用基于树的地图很容易实现这一点。
作为旁注,如果您没有该限制且间隔可能重叠 - 您可能需要intervals tree的变体。
(1)关于“最接近”的澄清:你需要一次搜寻:(假设存储下限):找到最接近的较小/相等的值。检查它是否适合该范围。这在基于树的地图中以对数时间轻松完成。
如果你存储更高的界限,你需要反过来。
答案 1 :(得分:0)
List<Tuple<string, double, double>> ElmList = new List<Tuple<string, double, double>>();
private void LoadTuple()
{
ElmList.Add(new Tuple<string, double, double>("Element 1", 0.0, 1.39));
ElmList.Add(new Tuple<string, double, double>("Element 2", 1.4, 2.09));
ElmList.Add(new Tuple<string, double, double>("Element 3", 2.1, 4.89));
ElmList.Add(new Tuple<string, double, double>("Element 4", 4.9, 5.0));
}
private void button2_Click(object sender, EventArgs e)
{
double temp = double.Parse(textBox1.Text);
var element = ElmList.FirstOrDefault(x => x.Item2 <= temp && x.Item3 >= temp);
MessageBox.Show(element.Item1);
}
将会解决您的问题,我尝试过类似上面的内容
答案 2 :(得分:0)
您可以尝试创建搜索树。您将必须根据里程碑对范围进行分组,例如1到5.然后,我们将创建一个字典,将这些milstones作为键,并将更接近这些里程碑的范围作为值。
Key Value
1 0.0-1.39
2 0.0-1.39, 1.4-2.09
3 2.1-4.89
4 2.1-4.89
5 2.1-4.89, 4.9-5.0
当我们试图找到一个数字落差的范围时,
您可能必须根据您的范围以不同方式定义里程碑。
答案 3 :(得分:0)
我认为您可以简单地使用二叉搜索树,或者更好的AVL(如果您不期望大量插入或删除)。
示例代码:使用跨树遍历的上限值(使用此repository中的bitlush的AVL实现)
class Range<T> where T : IComparable<T>
{
public T LBound { get; set; }
public T UBound { get; set; }
public bool ContainsValue(T value)
{
return (this.LBound.CompareTo(value) <= 0) && (value.CompareTo(this.UBound) <= 0);
}
}
class RangeKeyComparer : IComparer<Range<double>>
{
public int Compare(Range<double> x, Range<double> y)
{
return x.UBound.CompareTo(y.UBound);
}
}
class RangeAvlTree<T, TValue> : AvlTree<Range<T>, TValue> where T : IComparable<T>
{
public RangeAvlTree(IComparer<Range<T>> comparer)
{
//update access modifier to 'protected' in base class
_comparer = comparer;
}
public bool Search(T searchKey, out TValue value)
{
//update access modifier to 'protected' in base class
AvlNode<Range<T>, TValue> node = _root;
while (node != null)
{
if (node.Key.ContainsValue(searchKey))
{
value = node.Value;
return true;
}
else if (searchKey.CompareTo(node.Key.UBound) == 1)
node = node.Right;
else if (searchKey.CompareTo(node.Key.UBound) == -1)
node = node.Left;
}
value = default(TValue);
return false;
}
}
<强>用法强>
static void Main(string[] args)
{
var tree = new RangeAvlTree<double, string>(new RangeKeyComparer());
tree.Insert(new Range<double> { LBound = 0.0, UBound = 1.39 }, "Element: 0.0 - 1.39");
tree.Insert(new Range<double> { LBound = 1.4, UBound = 2.09 }, "Element: 1.4 - 2.09");
tree.Insert(new Range<double> { LBound = 2.1, UBound = 4.89 }, "Element: 2.1 - 4.89");
tree.Insert(new Range<double> { LBound = 4.9, UBound = 5.0 }, "Element: 4.9 - 5.00");
string element;
foreach(var value in new[] { 0.1, 1.41, 3, 2.04, 2.092, 4.93, 3.4 })
if (tree.Search(value, out element))
Console.WriteLine($"Found match: {value} matches {element}");
else
Console.WriteLine($"Not found: {value}");
Console.ReadLine();
}