C# 如何使用C搜索范围内的值#
我有一个这样的值列表C# 如何使用C搜索范围内的值#,c#,algorithm,C#,Algorithm,我有一个这样的值列表 1000, 20400 22200, 24444 范围不重叠 我想做的是有一个c#函数,它可以存储(从db加载的值,然后在本地缓存)这些值的相对较大的列表,然后有一个方法来查找提供的值是否在任何范围内 这有意义吗 需要最快的解决方案您已经指定了值,但随后谈到了范围 对于仅值,我将使用哈希集。对于范围,它变得更复杂。。。让我们知道这是否是你真正想要的,我会仔细考虑的。如果它们是范围,您有关于它们的额外信息吗?你知道它们是否会重叠吗?您只是对某个范围的存在感兴趣,还是需要找到
1000, 20400
22200, 24444
范围不重叠
我想做的是有一个c#函数,它可以存储(从db加载的值,然后在本地缓存)这些值的相对较大的列表,然后有一个方法来查找提供的值是否在任何范围内
这有意义吗
需要最快的解决方案您已经指定了值,但随后谈到了范围 对于仅值,我将使用
哈希集
。对于范围,它变得更复杂。。。让我们知道这是否是你真正想要的,我会仔细考虑的。如果它们是范围,您有关于它们的额外信息吗?你知道它们是否会重叠吗?您只是对某个范围的存在感兴趣,还是需要找到某个值所属的所有范围
编辑:通过对问题的编辑,巴里的答案完全正确。只需在初始化时进行排序(按下限排序就足够了),然后进行二进制搜索,以找到包含该值的范围,或者不包含该值
编辑:我最近在中找到了下面的代码
需要事先对范围进行排序-列表。如果没有重叠,则排序可以正常工作
public class Range : IComparable<Range>
{
private readonly int bottom; // Add properties for these if you want
private readonly int top;
public Range(int bottom, int top)
{
this.bottom = bottom;
this.top = top;
}
public int CompareTo(Range other)
{
if (bottom < other.bottom && top < other.top)
{
return -1;
}
if (bottom > other.bottom && top > other.top)
{
return 1;
}
if (bottom == other.bottom && top == other.top)
{
return 0;
}
throw new ArgumentException("Incomparable values (overlapping)");
}
/// <summary>
/// Returns 0 if value is in the specified range;
/// less than 0 if value is above the range;
/// greater than 0 if value is below the range.
/// </summary>
public int CompareTo(int value)
{
if (value < bottom)
{
return 1;
}
if (value > top)
{
return -1;
}
return 0;
}
}
// Just an existence search
public static bool BinarySearch(IList<Range> ranges, int value)
{
int min = 0;
int max = ranges.Count-1;
while (min <= max)
{
int mid = (min + max) / 2;
int comparison = ranges[mid].CompareTo(value);
if (comparison == 0)
{
return true;
}
if (comparison < 0)
{
min = mid+1;
}
else if (comparison > 0)
{
max = mid-1;
}
}
return false;
}
公共类范围:i可比较
{
private readonly int bottom;//如果需要,可以添加这些属性
私有只读int-top;
公共范围(整数底部、整数顶部)
{
this.bottom=底部;
this.top=top;
}
公共整数比较(范围其他)
{
if(底部<其他.bottom&&top<其他.top)
{
返回-1;
}
如果(底部>其他.bottom&&top>其他.top)
{
返回1;
}
if(bottom==other.bottom&&top==other.top)
{
返回0;
}
抛出新的ArgumentException(“不可比较的值(重叠)”;
}
///
///如果值在指定范围内,则返回0;
///如果值高于范围,则小于0;
///如果值低于范围,则大于0。
///
公共整数比较(整数值)
{
如果(值<底部)
{
返回1;
}
如果(值>顶部)
{
返回-1;
}
返回0;
}
}
//只是一个生存搜索
公共静态布尔二进制搜索(IList范围,int值)
{
int min=0;
int max=范围。计数-1;
而(最小0)
{
max=mid-1;
}
}
返回false;
}
二进制搜索就可以了。保持区域列表的排序顺序,确保所有区域都不相交(如果相交,则合并)。然后编写一个二进制搜索,它不是针对单个值进行测试,而是针对范围的任意一端进行测试,以选择上面或下面的选项。我会先尝试最简单的选项,如果不满足您的需要,则进行优化
class Range {
int Lower { get; set; }
int Upper { get; set; }
}
List<Range>.FirstOrDefault(r => i >= r.Lower && i <= r.Upper);
类范围{
int Lower{get;set;}
整数上限{get;set;}
}
List.FirstOrDefault(r=>i>=r.Lower&&i假设范围不重叠:
->将您的所有范围编号放入一个数组中
->对数组进行排序
->同时为startValue保留一个哈希集
->现在对您的号码进行二进制搜索。有两种可能:
-->您的数字左边(小于)的数组范围是一个起始值:您的
数字在范围内
-->您的数字左边(小于)的数组范围不是起始值:您的
数字不在范围内
这在功能上是您所追求的吗?如果是这样,您只是希望它更高效,而不是将ValueRangeCollection中的foreach更改为二进制搜索
public struct ValueRange
{
public int LowVal;
public int HiVal;
public bool Contains (int CandidateValue)
{ return CandidateValue >= LowVal && CandidateValue <= HiVal; }
public ValueRange(int loVal, int hiVal)
{
LowVal = loVal;
HiVal = hiVal;
}
}
public class ValueRangeCollection: SortedList<int, ValueRange>
{
public bool Contains(int candValue)
{
foreach ( ValueRange valRng in Values)
if (valRng.Contains(candValue)) return true;
return false;
}
public void Add(int loValue, int hiValue)
{
Add(loValue, new ValueRange(loValue, hiValue));
}
}
public结构值范围
{
公共国际组织;
公共国际组织;
公共布尔包含(int CandidateValue)
{return CandidateValue>=LowVal&&CandidateValue类范围
{
public int Start{get;set;}
公共int End{get;set;}
静态字典值;
静态int[]arrtobinarysarchin;
公共静态void BuildRanges(IEnumerable ranges){
值=新字典();
foreach(范围内的var项目)
值[项目.开始]=项目;
arrtobinarysarcin=values.Keys.ToArray();
Array.Sort(arrtobinarysarcin);
}
公共静态范围GetRange(int值)
{
int searchIndex=Array.BinarySearch(arrtobinarysarchin,value);
如果(搜索索引<0)
searchIndex=~searchIndex-1;
如果(搜索索引<0)
返回null;
建议的范围范围=值[arrtobinarysarchin[searchIndex]];
如果(proposedRange.End>=值)
返回建议的范围;
返回null;
}
}
类别范围
{
int[]start=new[]{100022200};
int[]end=new[]{20400,24444};
公共整数范围索引(整数测试)
{
int指数=-1;
如前所述,如果(test>=开始[0]&&test,如果范围集很大且不重叠,最好进行二进制搜索。一种方法是使用SortedDictionary
,它实现了一个红黑树来给出一个O(log(n))搜索时间。我们可以使用范围作为键,并通过将要匹配的单个值转换为单个点的范围来执行字典查找。如果我们实现CompareTo
方法,以便重叠的范围被视为相等/匹配,字典查找将查找匹配范围以供使用
public struct Range : IComparable<Range>
{
public int From;
public int To;
public Range(int point)
{
From = point;
To = point;
}
public Range(int from, int to)
{
From = from;
To = to;
}
public int CompareTo(Range other)
{
// If the ranges are overlapping, they are considered equal/matching
if (From <= other.To && To >= other.From)
{
return 0;
}
// Since the ranges are not overlapping, we can compare either end
return From.CompareTo(other.From);
}
}
public class RangeDictionary
{
private static SortedDictionary<Range, string> _ranges = new SortedDictionary<Range, string>();
public RangeDictionary()
{
_ranges.Add(new Range(1, 1000), "Alice");
_ranges.Add(new Range(1001, 2000), "Bob");
_ranges.Add(new Range(2001, 3000), "Carol");
}
public string Lookup(int key)
{
/* We convert the value we want to lookup into a range,
* so it can be compared with the other ranges */
var keyAsRange = new Range(key);
string value;
if (_ranges.TryGetValue(keyAsRange, out value))
{
return value;
}
return null;
}
}
在这种情况下,值将包含字符串“Bob”
,因为1356与范围1001-2000匹配
在您的例子中,如果您对获取范围本身感兴趣,您可以在字典中使用该范围作为键和值。示例代码可以很容易地扩展为保存泛型值
作为sid
class Ranges
{
int[] starts = new[] { 1000, 22200 };
int[] ends = new[] { 20400, 24444 };
public int RangeIndex(int test)
{
int index = -1;
if (test >= starts[0] && test <= ends[ends.Length - 1])
{
index = Array.BinarySearch(ends, test);
if (index <= 0)
{
index = ~index;
if (starts[index] > test) index = -1;
}
}
return index;
}
}
public struct Range : IComparable<Range>
{
public int From;
public int To;
public Range(int point)
{
From = point;
To = point;
}
public Range(int from, int to)
{
From = from;
To = to;
}
public int CompareTo(Range other)
{
// If the ranges are overlapping, they are considered equal/matching
if (From <= other.To && To >= other.From)
{
return 0;
}
// Since the ranges are not overlapping, we can compare either end
return From.CompareTo(other.From);
}
}
public class RangeDictionary
{
private static SortedDictionary<Range, string> _ranges = new SortedDictionary<Range, string>();
public RangeDictionary()
{
_ranges.Add(new Range(1, 1000), "Alice");
_ranges.Add(new Range(1001, 2000), "Bob");
_ranges.Add(new Range(2001, 3000), "Carol");
}
public string Lookup(int key)
{
/* We convert the value we want to lookup into a range,
* so it can be compared with the other ranges */
var keyAsRange = new Range(key);
string value;
if (_ranges.TryGetValue(keyAsRange, out value))
{
return value;
}
return null;
}
}
var ranges = new RangeDictionary();
var value = ranges.Lookup(1356);