字典排序自定义关键字查找以提高效率

问题描述

最近,我了解到Sorted Dictionary类在键上实现了二进制搜索,我想以此为自己的优势。我正在制作一个piecewise线性函数类,它表示一系列间隔上的线集合。

我这样定义了Interval类:

public class Interval : ICloneable,IComparable,IComparable<Interval>
{
    public Interval()
    {

    }
    public Interval(double start,double end)
    {
        Start = start;
        End = end;
    }

    // Properties
    public double Start { get; set; } = double.NaN;
    public double End { get; set; } = double.NaN;
    public double Span => End - Start;

    // Methods
    public object Clone() => MemberwiseClone();

    public int CompareTo(object obj)
    {
        return Start.CompareTo(obj);
    }

    public int CompareTo([AllowNull] Interval other)
    {
        if (Start < other.Start)
        {
            return -1;
        }
        else if (Start > other.Start)
        {
            return 1;
        }
        else
        {
            return 0;
        }
    }

    public bool Contains(double x) => Start <= x && x <= End;
    public override string ToString() => $"[{Start},{End}]";
}

有问题的SortedDictionary在分段函数类中的工作方式如下:

public class PiecewiseLinearFunction : ICloneable
{
    ...
    // The dictionary
    public SortedDictionary<Interval,Line2D> Functions { get; set; } = new SortedDictionary<Interval,Line2D>(); // Where Line2D is just a class that contains a function definition for a line

    // Methods
    public Interval FindInterval(double x)
        => Functions.Keys.Where(interval => interval.Contains(x)).FirstOrDefault();
    public double Solve(double x)
    {
        var interval = FindInterval(x);
        if (interval != null && Functions.ContainsKey(interval))
        {
            return Functions[interval].Solve(x);
        }
        else
        {
            return double.NaN;
        }
    }
}

如您所见,PiecewiseLinearFunction.FindInterval(double x)方法线性搜索字典的键,以查找包含(或不包含)x的间隔,该间隔可用于二进制外观-up,但这显然会破坏进行二进制查找的目的。

我想知道是否可以以某种方式使字典查找double x值,并在检查Interval.Contains(double x)true还是{{1 }}来确定是否存在有效的间隔(键)和相应的行,这些行可用于获取false处的函数值。

换句话说,有没有一种方法可以搜索谓词,例如x

解决方法

因此,如果间隔不重叠,则实际上实际上不需要自定义二进制搜索。

首先,如果我们使Intervaldouble具有可比性,那么它会有所帮助:

public class Interval: IComparable<double>
{
    public double Start { get; set; }
    public double End { get; set; }

    public bool Contains(double x) => x >= Start && x <= End;
    public int CompareTo(double other)
    {
        if (Contains(other))
            return 0;
        return other < Start ? 1 : -1;
    }
}

现在,我们创建一个List扩展名,以便能够使用其他类型(仅列表类型)进行二进制搜索:

public static class ListExtensions
{
    public static int BinarySearch<T,TU>(this List<T> sortedSource,TU val) where T : IComparable<TU>
    {
        return sortedSource.BinarySearch(default(T),Comparer<T>.Create((item,_) => item.CompareTo(val)));
    }
}

现在我们可以像这样测试它了:

var list = new List<Interval>
{
    new Interval
    {
        Start = 0,End = 4
    },new Interval
    {
        Start = 6,End = 7
    },new Interval
    {
        Start = 10,End = 12
    }
};

var index = list.BinarySearch(6.0d); //index = 1
var interval = index < 0 ? null : list[index]; //interval = [6,7]

index = list.BinarySearch(9.0d); //index = -3
interval = index < 0 ? null : list[index]; //interval = null

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...