C# - 允许您根据范围内的值访问元素的数据结构

时间:2017-05-26 08:50:43

标签: c# data-structures

我有一个对象列表。它们都与该对象唯一的范围相关联。没有重叠。我想要一种方法来尽可能快地访问与该范围相关联的对象。目前的数据结构都不适合这种情况。这是一个图表:

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.

后备是一个列表,但这意味着每次迭代它,根据大小,它理论上可能会变慢。

4 个答案:

答案 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

当我们试图找到一个数字落差的范围时,

  1. 我们会在数字
  2. 上做一个Math.Ceil()
  3. 将其与字典中的里程碑相匹配,并找到该键的范围列表
  4. 现在遍历里程碑下的范围,找到包含数字的范围
  5. 您可能必须根据您的范围以不同方式定义里程碑。

答案 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();
}